(use-package no-littering
:ensure t
:custom
(no-littering-var-directory (expand-file-name "data/" user-emacs-directory)))
(use-package subr-x)
(setq home-directory (getenv "HOME"))
(setq config-basedir
(file-name-directory
(or (buffer-file-name) load-file-name)))
(defun concat-normalize-slashes (prefix suffix)
(concat "/"
(string-join
(split-string
(string-join (list prefix suffix) "/") "/" t) "/")))
(defun at-homedir (&optional suffix)
(concat-normalize-slashes home-directory suffix))
(defun at-org-dir (&optional suffix)
(concat-normalize-slashes (at-homedir "/docs/org")
suffix))
(defun at-org-kb-dir (&optional suffix)
(concat-normalize-slashes (at-homedir "/docs/org-kb")
suffix))
(defun at-config-basedir (&optional suffix)
(concat-normalize-slashes config-basedir suffix))
(defun at-user-data-dir (&optional suffix)
(concat-normalize-slashes no-littering-var-directory suffix))
(defun at-workspace-dir (&optional suffix)
(concat-normalize-slashes (at-homedir "/workspace") suffix))
(defvar enable-experimental-packages nil)
(load (at-config-basedir "credentials.el.gpg"))
(use-package auto-compile
:ensure t
:config
(auto-compile-on-load-mode 1)
(auto-compile-on-save-mode 1)
:custom
(auto-compile-display-buffer nil)
(auto-compile-mode-line-counter t))
(use-package f
:ensure t
:after (s dash))
(use-package names :ensure t)
(use-package anaphora :ensure t)
(use-package delight :ensure t)
(use-package notifications)
(use-package cus-edit
:hook (kill-emacs-hook . (lambda () (delete-file custom-file)))
:custom
(custom-file (at-config-basedir "customizations.el")))
(use-package emacs
:general
("M-\"" 'eval-region)
([remap kill-buffer] 'kill-this-buffer)
:config
(fset 'yes-or-no-p 'y-or-n-p)
(setq scalable-fonts-allowed t)
(setq use-dialog-box nil)
(setq enable-recursive-minibuffers t)
;; don't let the cursor go into minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt))
(when (eq system-type 'gnu-linux)
(setq x-alt-keysym 'meta))
(put 'downcase-region 'disabled nil)
(put 'erase-buffer 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'scroll-left 'disabled nil)
(put 'scroll-right 'disabled nil)
(put 'upcase-region 'disabled nil)
(setq scroll-preserve-screen-position 'always)
;; reduce point movement lag, see https://emacs.stackexchange.com/questions/28736/emacs-pointcursor-movement-lag/28746
(setq auto-window-vscroll nil)
(setq undo-limit 1000000)
(advice-add 'undo-auto--last-boundary-amalgamating-number :override #'ignore) ;; https://stackoverflow.com/a/41560712/2112489
(setq indent-tabs-mode nil)
(set-default 'indent-tabs-mode nil);; Never insert tabs, !!!DO NOT REMOVE!!!
(setq-default tab-width 4)
(setq mark-even-if-inactive nil)
(setq-default fill-column 200)
(setq-default indicate-empty-lines t)
(setq-default truncate-lines t)
(setq x-stretch-cursor t)
(setq user-full-name (capitalize private/real-name))
;; print symbols
(setq print-circle t)
(setq print-gensym t)
;; encodings
(setq locale-coding-system 'utf-8)
(define-coding-system-alias 'UTF-8 'utf-8)
(define-coding-system-alias 'utf-8-emacs 'utf-8) ; needed by bbdb...
(define-coding-system-alias 'utf_8 'utf-8)
(set-default buffer-file-coding-system 'utf-8-unix)
(setq sentence-end-double-space nil)
(setq tab-always-indent t)
(setq frame-inhibit-implied-resize nil)
(setq split-width-threshold nil)
(setq split-height-threshold nil)
(setq same-window-buffer-names
'("*Help*")))
(setq default-input-method 'russian-computer)
Reverse input method makes Emacs with non-English system keyboard layout to behave correctly with keybindings. It definitely makes sense while using Emacs in such X WMs when there is no chance to hook into keyboard layouts switching (those are probably all, except StumpWM/XMonad, AFAIK)
(use-package reverse-im
:ensure t
:if (not (member (getenv "CURRENT_WM") '("stumpwm" "xmonad")))
:config
(reverse-im-activate "russian-computer"))
(use-package auth-source
:custom
;;TODO: investigate and setup ghub according to https://github.com/magit/ghub/blob/master/ghub.org#user-content-manually-creating-and-storing-a-token
;;TODO: check if it needed and resurrect .authinfo.gpg
(auth-sources '("~/.authinfo.gpg")))
(use-package epa
:after (epg)
:config
(epa-file-enable)
:custom
(epa-pinentry-mode 'loopback))
(use-package epg-config
:after (epg)
:custom
(epg-gpg-program "gpg2")
(epg-gpg-home-directory "~/.gnupg"))
(use-package password-cache
:custom
(password-cache-expiry nil)
(password-cache t))
(use-package keychain-environment
:ensure t
:config
(keychain-refresh-environment))
(setq gc-cons-percentage 0.3)
(setq gc-cons-threshold most-positive-fixnum)
(add-hook 'after-init-hook #'(lambda ()
(setq gc-cons-threshold 800000)))
(add-hook 'minibuffer-setup-hook (lambda () (setq gc-cons-threshold most-positive-fixnum)))
(add-hook 'minibuffer-exit-hook (lambda () (setq gc-cons-threshold 800000)))
(add-hook 'focus-out-hook #'garbage-collect)
(use-package mule
:config
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-buffer-file-coding-system 'utf-8 'utf-8-unix)
(set-selection-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-clipboard-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8))
(use-package font-core
:config
(global-font-lock-mode 1))
(use-package font-lock
:preface
(defun custom/highlight-keywords ()
;; highlight additional keywords
(font-lock-add-keywords nil '(("\\<\\(FIXME\\|FIX_ME\\|FIX ME\\):" 1 font-lock-warning-face t)))
(font-lock-add-keywords nil '(("\\<\\(BUG\\|BUGS\\):" 1 font-lock-warning-face t)))
(font-lock-add-keywords nil '(("\\<\\(TODO\\|TO DO\\NOTE\\|TBD\\):" 1 font-lock-warning-face t)))
(font-lock-add-keywords nil '(("\\<\\(DONE\\|HACK\\):" 1 font-lock-doc-face t)))
;; highlight too long lines
(font-lock-add-keywords nil '(("^[^\n]\\{120\\}\\(.*\\)$" 1 font-lock-warning-face t))))
:hook ((emacs-lisp-mode-hook lisp-mode-hook python-mode-hook) . custom/highlight-keywords)
:config
(setq font-lock-maximum-decoration t))
(use-package face-remap
:general
("C-=" 'text-scale-increase)
("C--" 'text-scale-decrease))
(use-package unicode-fonts
:ensure t
:after (persistent-soft)
:config
(unicode-fonts-setup))
(use-package doom-modeline
:ensure t
:custom
(doom-modeline-height 25)
(doom-modeline-icon t)
(doom-modeline-major-mode-icon nil)
(doom-modeline-minor-modes nil)
:config
(doom-modeline 1))
(use-package nord-theme :ensure t :config (load-theme 'nord t) :disabled)
(use-package kaolin-themes :ensure t :config (load-theme 'kaolin-dark t) :disabled)
(use-package hc-zenburn-theme :ensure t :config (load-theme 'hc-zenburn t))
(use-package darkburn-theme :ensure t :config (load-theme 'darkburn t) :disabled)
(use-package solarized-theme :ensure t :config (load-theme 'solarized-dark t) :disabled)
;; Providing dark enough colors, unless we are using an appropriate theme, Darkburn, for example
(when (boundp 'zenburn-colors-alist)
(set-face-attribute 'default nil :background "#1A1A1A")
(set-face-attribute 'region nil :background (cdr (assoc "zenburn-bg-2" zenburn-colors-alist))))
(use-package tooltip
:config
(tooltip-mode 0))
(use-package avoid
:config
(mouse-avoidance-mode 'jump))
(use-package frame
:preface
(defvar opacity-percent 75 "Opacity percent")
(defun custom/toggle-transparency ()
(interactive)
(let ((alpha (frame-parameter nil 'alpha)))
(set-frame-parameter
nil 'alpha
(if (eql (cond ((numberp alpha) alpha)
((numberp (cdr alpha))
(cdr alpha))
;; Also handle undocumented (<active> <inactive>) form.
((numberp (cadr alpha)) (cadr alpha)))
100)
`(,opacity-percent . 50) '(100 . 100)))))
:general
("M-o" 'ace-window)
(:prefix "<f2>"
"n" 'make-frame-command
"k" 'delete-frame
"s" 'delete-other-frames
"v" 'custom/toggle-transparency)
:config
(general-unbind 'global "M-o")
(add-to-list 'default-frame-alist `(alpha . (100 . 100)))
(blink-cursor-mode 0)
(set-frame-parameter (selected-frame) 'alpha '(100 . 100))
(setq frame-title-format "emacs - %b %f") ;; for various external tools
(setq opacity-percent 75)
(setq truncate-partial-width-windows nil))
(use-package tool-bar
:config
(tool-bar-mode -1))
(use-package scroll-bar
:config
(scroll-bar-mode -1)
(when (>= emacs-major-version 25)
(horizontal-scroll-bar-mode -1)))
(use-package menu-bar
:general
(:keymaps 'mode-specific-map
"b" 'toggle-debug-on-error
"q" 'toggle-debug-on-quit)
:config
(menu-bar-mode -1))
(use-package popwin :ensure t)
(use-package hl-line
:config
(global-hl-line-mode 1))
(use-package time
:config
(display-time)
:custom
(display-time-day-and-date t)
;; (display-time-form-list (list 'time 'load))
(display-time-world-list
'(("Europe/Moscow" "Moscow")))
(display-time-mail-file t)
(display-time-default-load-average nil)
(display-time-24hr-format t)
(display-time-string-forms '( day " " monthname " (" dayname ") " 24-hours ":" minutes)))
(use-package uniquify
:custom
(uniquify-buffer-name-style 'post-forward)
(uniquify-separator ":")
(uniquify-ignore-buffers-re "^\\*")
(uniquify-strip-common-suffix nil))
(use-package savehist
:config
(savehist-mode t)
:custom
(savehist-save-minibuffer-history t)
(savehist-autosave-interval 60)
(history-length 10000)
(history-delete-duplicates t)
(savehist-additional-variables
'(kill-ring
search-ring
regexp-search-ring)))
(use-package backup-each-save
:ensure t
:hook (after-save-hook . backup-each-save))
(use-package super-save
:ensure t
:delight super-save-mode
:custom
(super-save-remote-files nil)
:config
(super-save-mode 1))
maintain recent files
(use-package recentf
:no-require t
:defer 1
:config
(use-package recentf-ext :ensure t)
(add-to-list 'recentf-exclude no-littering-var-directory)
(add-to-list 'recentf-exclude no-littering-etc-directory)
(recentf-mode t)
:custom
(recentf-max-saved-items 250)
(recentf-max-menu-items 15))
Simultaneous edits still will be detected when saving is made. But disabling lock files prevents our working dirs from being clobbered with.
(setf create-lockfiles nil)
(use-package server
:defer 2
:preface
(defun custom/server-save-edit ()
(interactive)
(save-buffer)
(server-edit))
(defun custom/save-buffer-clients-on-exit ()
(interactive)
(if (and (boundp 'server-buffer-clients) server-buffer-clients)
(server-save-edit)
(save-buffers-kill-emacs t)))
:hook (server-visit-hook . (lambda () (local-set-key (kbd "C-c C-c") 'custom/server-save-edit)))
:config
(unless (and (string-equal "root" (getenv "USER"))
(server-running-p))
(require 'server)
(server-start))
(advice-add 'save-buffers-kill-terminal :before 'custom/save-buffer-clients-on-exit))
(use-package amx
:ensure t
:general ("M-x" 'amx)
:custom
(amx-backend 'ivy)
(amx-save-file (at-user-data-dir "amx-items")))
(use-package tramp
:config
(setq tramp-default-method "ssh")
(setq tramp-ssh-controlmaster-options "")
(setq tramp-default-proxies-alist nil))
(use-package paradox
:ensure t
:after (seq let-alist spinner)
:commands paradox-list-packages
:custom
(paradox-execute-asynchronously t)
(paradox-column-width-package 27)
(paradox-column-width-version 13)
(paradox-github-token private/paradox-github-token)
:config
(remove-hook 'paradox-after-execute-functions #'paradox--report-buffer-print))
;; for some reason feature 'files' provided with use-package
;; brings more headache than it deserves, so a little bit of
;; dirty imperative style below (still hope on fixing it later)
(defun custom/untabify-buffer ()
(when (member major-mode '(haskell-mode
emacs-lisp-mode
lisp-mode
python-mode))
(untabify (point-min) (point-max))))
(add-hook 'before-save-hook #'delete-trailing-whitespace)
(add-hook 'before-save-hook #'custom/untabify-buffer)
(when (> emacs-major-version 25) (auto-save-visited-mode 1))
(setq require-final-newline t)
(setq enable-local-variables nil)
;; backup settings
(setq auto-save-default nil)
(setq backup-by-copying t)
(setq backup-by-copying-when-linked t)
(setq backup-directory-alist '(("." . "~/.cache/emacs/backups")))
(setq delete-old-versions -1)
(setq kept-new-versions 6)
(setq kept-old-versions 2)
(setq version-control t)
(setq save-abbrevs 'silently)
(global-set-key (kbd "C-x f") 'find-file) ; I never use set-fill-column and I hate hitting it by accident.
(use-package novice
:config
(setq disabled-command-function nil))
(use-package which-key
:ensure t
:config
(which-key-setup-side-window-right)
(which-key-mode))
(use-package ibuffer
:commands ibuffer
:general
([remap list-buffers] 'ibuffer)
(:keymaps 'ibuffer-mode-map
"/ ." '(lambda (qualifier)
(interactive "sFilter by extname: ")
(ibuffer-filter-by-filename (concat "\\." qualifier "$")))
"M-o" 'other-window) ; was ibuffer-visit-buffer-1-window
:hook (ibuffer-mode-hook . (lambda ()
;; Make sure we're always using our buffer groups
(ibuffer-switch-to-saved-filter-groups "default")))
:custom
(ibuffer-default-sorting-mode 'major-mode) ;recency
(ibuffer-always-show-last-buffer :nomini)
(ibuffer-default-shrink-to-minimum-size t)
(ibuffer-jump-offer-only-visible-buffers t)
(ibuffer-saved-filters
'(("dired" ((mode . dired-mode)))
("foss" ((filename . "foss")))
("pets" ((filename . "pets")))
("jabberchat" ((mode . jabber-chat-mode)))
("orgmode" ((mode . org-mode)))
("elisp" ((mode . emacs-lisp-mode)))
("fundamental" ((mode . fundamental-mode)))
("haskell" ((mode . haskell-mode)))))
(ibuffer-saved-filter-groups custom/ibuffer-saved-filter-groups))
(use-package ibuffer-vc
:ensure t
:disabled
:hook (ibuffer-hook . (lambda ()
(ibuffer-vc-set-filter-groups-by-vc-root)
(unless (eq ibuffer-sorting-mode 'alphabetic)
(ibuffer-do-sort-by-alphabetic))))
: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"))
(use-package ibuffer-project
:ensure t
:hook ((ibuffer-hook . (lambda () (setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups))))
(ibuffer-hook . (lambda ()
(setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups))
(unless (eq ibuffer-sorting-mode 'project-file-relative)
(ibuffer-do-sort-by-project-file-relative)))))
:custom
(ibuffer-formats
'((mark modified read-only locked " "
(name 18 18 :left :elide)
" "
(size 9 -1 :right)
" "
(mode 16 16 :left :elide)
" " project-file-relative))))
(use-package ivy
:ensure t
:delight ivy-mode
:general
("M-<f12>" 'ivy-switch-buffer)
("<f10>" 'ivy-resume)
(:keymaps 'ctl-x-map
"b" 'ivy-switch-buffer)
(:keymaps 'mode-specific-map
"v" 'ivy-push-view
"V" 'ivy-pop-view)
(:keymaps 'ivy-minibuffer-map
"C-j" 'ivy-immediate-done)
:config
(general-unbind 'global "C-x C-b")
(ivy-mode 1)
:custom-face
(ivy-current-match ((t (:background "gray1"))))
:custom
(ivy-display-style 'fancy)
(ivy-use-selectable-prompt t "Make the prompt line selectable")
(ivy-use-virtual-buffers t) ;; add 'recentf-mode’and bookmarks to 'ivy-switch-buffer'.
(ivy-height 20) ;; number of result lines to display
(ivy-count-format "%d/%d ")
(ivy-initial-inputs-alist nil) ;; no regexp by default
(ivy-re-builders-alist
;; allow input not in order
'((read-file-name-internal . ivy--regex-fuzzy)
(t . ivy--regex-ignore-order))))
(use-package counsel
:ensure t
:defer 2
:after (swiper)
:delight counsel-mode
:preface
(defun custom/open-org-file ()
(interactive)
(ivy-read "Org files: "
(funcall #'(lambda () (f-files (at-org-dir) nil t)))
:action #'(lambda (candidate)
(find-file candidate))
:require-match t
:caller 'custom/open-org-file))
(defun custom/open-org-kb-file ()
(interactive)
(ivy-read "Org files: "
(funcall #'(lambda () (f-files (at-org-kb-dir) nil t)))
:action #'(lambda (candidate)
(find-file candidate))
:require-match t
:caller 'custom/open-org-kb-file))
:init
(require 'iso-transl)
:general
([remap menu-bar-open] 'counsel-tmm)
([remap insert-char] 'counsel-unicode-char)
([remap isearch-forward] 'counsel-grep-or-swiper)
(:keymaps 'mode-specific-map
"C-SPC" 'counsel-mark-ring
"C-." 'counsel-fzf
"w" 'counsel-wmctrl
"O" 'custom/open-org-file
"K" 'custom/open-org-kb-file)
(:keymaps 'ctl-x-map
"C-r" 'counsel-recentf)
("C-h L" 'counsel-locate)
(:prefix "<f9>"
"y" 'counsel-yank-pop
"m" 'counsel-mark-ring
"c" 'counsel-command-history
"e" 'counsel-expression-history
"p" 'counsel-package
"l" 'counsel-git-log
"g" 'counsel-rg
"G" '(lambda () (interactive) (counsel-rg (thing-at-point 'symbol)))
"m" 'swiper-multi
"I" 'ivy-imenu-anywhere)
(:keymaps 'help-map
"l" 'counsel-find-library)
(:prefix "<f1>"
"l" 'counsel-find-library
"b" 'counsel-descbinds
"i" 'counsel-info-lookup-symbol)
(:keymaps 'iso-transl-ctl-x-8-map
"RET" 'counsel-unicode-char)
(:keymaps 'ivy-minibuffer-map
"M-y" 'ivy-next-line)
:custom
(counsel-git-cmd "rg --files")
(counsel-grep-base-command "rg -i -M 120 --no-heading --line-number --color never '%s' %s")
(counsel-rg-base-command "rg -i -M 120 --no-heading --line-number --color never %s .")
:config
(counsel-mode 1))
(use-package ivy-rich
:ensure t
:after (ivy)
:defines ivy-rich-abbreviate-paths ivy-rich-switch-buffer-name-max-length
:custom
(ivy-rich-switch-buffer-name-max-length 60 "Increase max length of buffer name.")
:config
(ivy-rich-mode 1))
(use-package ivy-xref
:ensure t
:custom
(xref-show-xrefs-function #'ivy-xref-show-xrefs "Use Ivy to show xrefs"))
(use-package ivy-dired-history
:ensure t
:after (dired savehist)
:config
(add-to-list 'savehist-additional-variables 'ivy-dired-history-variable))
(use-package ivy-historian
:ensure t
:config
(ivy-historian-mode))
(use-package link-hint
:ensure t
:general
(:keymaps 'mode-specific-map
"o s" 'custom/open-url-current-buffer
"o f" 'link-hint-open-link
"o y" 'link-hint-copy-link
"o F" 'link-hint-open-multiple-links
"o Y" 'link-hint-copy-multiple-links)
:custom
(link-hint-avy-style 'de-bruijn))
(use-package browse-url
:if (and (eq system-type 'gnu/linux)
(eq window-system 'x))
:preface
(defun custom/buffer-urls--candidates ()
(save-excursion
(save-restriction
(let ((urls))
(goto-char (point-min))
(while (re-search-forward org-plain-link-re nil t)
(push (thing-at-point 'url) urls))
(remove nil urls)))))
(defun custom/open-url-current-buffer ()
(interactive)
(ivy-read "URLs: "
(funcall #'custom/buffer-urls--candidates)
:action #'(lambda (candidate)
(browse-url candidate))
:require-match t
:caller 'custom/open-url-current-buffer))
(defun feh-browse (url &rest ignore)
"Browse image using feh."
(interactive (browse-url-interactive-arg "URL: "))
(start-process (concat "feh " url) nil "feh" url))
(defun mpv-browse (url &rest ignore)
"Browse video using mpv."
(interactive (browse-url-interactive-arg "URL: "))
(start-process (concat "mpv --loop-file=inf" url) nil "mpv" "--loop-file=inf" url))
:custom
(browse-url-browser-function 'browse-url-generic)
(browse-url-generic-program "xdg-open")
:config
(setq browse-url-browser-function
(append
(mapcar (lambda (re)
(cons re #'eww-browse-url))
private/browse-url-images-re)
(mapcar (lambda (re)
(cons re #'mpv-browse))
private/browse-url-videos-re)
'(("." . browse-url-xdg-open)))))
;;Make cursor stay in the same column when scrolling using pgup/dn.
;;Previously pgup/dn clobbers column position, moving it to the
;;beginning of the line.
;;<http://www.dotemacs.de/dotfiles/ElijahDaniel.emacs.html>
(defadvice custom/scroll-up (around ewd-scroll-up first act)
"Keep cursor in the same column."
(let ((col (current-column)))
ad-do-it
(move-to-column col)))
(defadvice custom/scroll-down (around ewd-scroll-down first act)
"Keep cursor in the same column."
(let ((col (current-column)))
ad-do-it
(move-to-column col)))
(use-package saveplace
:defer 1
:config
(save-place-mode 1))
(use-package on-screen :ensure t)
(use-package beginend
:ensure t
:delight beginend-global-mode beginend-prog-mode beginend-magit-status-mode
:config
(beginend-global-mode))
(use-package mwim
:ensure t
:general
([remap move-beginning-of-line] 'mwim-beginning-of-code-or-line)
([remap move-end-of-line] 'mwim-end-of-code-or-line))
(use-package smooth-scrolling :ensure t)
(use-package bln-mode
:ensure t
:general
(:keymaps 'mode-specific-map
"h" 'bln-backward-half
"j" 'bln-forward-half-v
"k" 'bln-backward-half-v
"l" 'bln-forward-half))
(use-package projectile
:ensure t
:delight (projectile-mode " prj")
:custom
(projectile-enable-caching t)
(projectile-require-project-root nil)
(projectile-completion-system 'ivy)
(projectile-track-known-projects-automatically t)
:config
(setq projectile-switch-project-action 'projectile-commander)
(projectile-mode 1))
(use-package counsel-projectile
:ensure t
:after (counsel projectile)
:preface
(defun custom/open-project-todos ()
(interactive)
(let ((todos-file (expand-file-name "todo.org" (projectile-project-root))))
(condition-case nil
(when (file-exists-p todos-file)
(find-file todos-file))
(error (message "Cannot find project todos")))))
(defun custom/ensure-project-switch-buffer (arg)
"Custom switch to buffer.
With universal argument ARG or when not in project, rely on
`ivy-switch-buffer'.
Otherwise, use `counsel-projectile-switch-to-buffer'."
(interactive "P")
(if (or arg
(not (projectile-project-p)))
(ivy-switch-buffer)
(counsel-projectile-switch-to-buffer)))
(defun custom/search-deadgrep ()
(interactive)
(let ((term (read-from-minibuffer "Search term: ")))
(deadgrep term)))
(defun counsel-projectile-switch-project-action-open-todos (project)
"Open project's TODOs."
(let ((projectile-switch-project-action #'custom/open-project-todos))
(counsel-projectile-switch-project-by-name project)))
(defun counsel-projectile-switch-project-action-deadgrep (project)
"Search in project with deadgrep."
(let ((projectile-switch-project-action #'custom/search-deadgrep))
(counsel-projectile-switch-project-by-name project)))
:general
(:keymaps 'ctl-x-map
"j j" 'counsel-projectile-switch-project
"b" 'custom/ensure-project-switch-buffer)
(:prefix "<f8>"
"i" 'projectile-invalidate-cache
"k" 'projectile-kill-buffers
"c" 'projectile-commander
"d" 'projectile-dired
"f" 'projectile-recentf
"t" 'custom/open-project-todos
"T" 'doom/ivy-tasks
"h" 'projectile-find-file)
:config
(counsel-projectile-mode 1)
(add-to-list 'counsel-projectile-switch-project-action
'("t" counsel-projectile-switch-project-action-open-todos "open project's todos") t)
(add-to-list 'counsel-projectile-switch-project-action
'("d" counsel-projectile-switch-project-action-deadgrep "search project with deadgrep") t)
(setq projectile-switch-project-action 'counsel-projectile-switch-project))
(use-package dired
:commands dired
:hook (dired-mode-hook . auto-revert-mode)
:general
([remap list-directory] 'dired)
(:keymaps 'dired-mode-map
"e" '(lambda ()
(interactive)
(when (derived-mode-p 'dired-mode)
(if (file-directory-p (dired-get-filename))
(message "Directories cannot be opened in EWW")
(eww-open-file (dired-get-file-for-visit)))))
"C-x C-k" 'dired-do-delete)
:preface
(defvar custom/large-file-ok-types
(rx "." (or "mp4" "mkv" "pdf") string-end)
"Regexp matching filenames which are definitely ok to visit,
even when the file is larger than `large-file-warning-threshold'.")
(defadvice abort-if-file-too-large (around custom/check-large-file-ok-types)
"If FILENAME matches `custom/large-file-ok-types', do not abort."
(unless (string-match-p custom/large-file-ok-types (ad-get-arg 2))
ad-do-it))
:custom
(dired-recursive-deletes 'top) ;; Allows recursive deletes
(dired-dwim-target t)
(dired-listing-switches "-lah1v --group-directories-first") ;;TODO: think of using TIME_STYLE env var
:config
(put 'dired-find-alternate-file 'disabled nil)
(ad-activate 'abort-if-file-too-large)
(use-package dired-filetype-face :ensure t)
(use-package wdired
:general
(:keymaps 'dired-mode-map
"r" 'wdired-change-to-wdired-mode)
:custom
(wdired-allow-to-change-permissions 'advanced))
(use-package dired-narrow
:ensure t
:general
(:keymaps 'dired-mode-map
"/" 'dired-narrow))
(use-package dired-quick-sort
:ensure t
:config
(dired-quick-sort-setup))
(use-package diredfl
:ensure t
:config
(diredfl-global-mode))
(use-package dired-x
:config
;; do not bind C-x C-j, it may be binded later
(setq dired-bind-jump nil))
(use-package dired-hide-dotfiles
:ensure t
:after (dired)
:general
(:keymaps 'dired-mode-map
"." 'dired-hide-dotfiles-mode)
:hook
(dired-mode . dired-hide-dotfiles-mode)))
;; Reload dired after making changes
(--each '(dired-do-rename
dired-create-directory
wdired-abort-changes)
(eval `(defadvice ,it (after revert-buffer activate)
(revert-buffer))))
(use-package deadgrep
:ensure t
:commands deadgrep
:general
(:keymaps 'mode-specific-map
"d" 'deadgrep))
(use-package socyl
:ensure t
:general
(:keymaps 'mode-specific-map
"r" 'socyl-search-regexp)
:custom
(socyl-backend 'ripgrep))
(use-package phi-search
:ensure t
:commands phi-search phi-search-backward
:hook (isearch-mode-hook . phi-search-from-isearch-mc/setup-keys)
:config
(use-package phi-search-mc
:ensure t
:config
(phi-search-mc/setup-keys)))
(use-package wgrep
:ensure t
:general
(:keymaps 'grep-mode-map
"C-x C-q" 'wgrep-change-to-wgrep-mode
"C-c C-c" 'wgrep-finish-edit))
(defadvice occur-mode-goto-occurrence (after close-occur activate)
(delete-other-windows))
(use-package imenu-anywhere
:ensure t
:commands ivy-imenu-anywhere)
;; inline tasks navigation
(use-package doom-todo-ivy
:quelpa
(doom-todo-ivy :repo "jsmestad/doom-todo-ivy" :fetcher github)
:hook (after-init . doom-todo-ivy))
(use-package winner
:config
(winner-mode 1))
(use-package windsize
:ensure t
:disabled ;;TODO: remap keys and reenable
:general
("C-s-k" 'windsize-up)
("C-s-j" 'windsize-down)
("C-s-h" 'windsize-left)
("C-s-l" 'windsize-right))
(use-package ace-window
:ensure t
:after (avy)
:commands ace-window
:custom
(aw-background nil)
(aw-leading-char-style 'char)
(aw-scope 'visible)
:config
(ace-window-display-mode 1)
:custom-face (aw-leading-char-face
((t (:inherit ace-jump-face-foreground
:foreground "green"
:height 0.1)))))
(use-package swiper
:ensure t
:commands swiper swiper-multi swiper-occur
:preface
(defun custom/swiper (&optional tap)
(interactive "P")
(if tap
(swiper (thing-at-point 'symbol))
(swiper)))
:general
("C-s" 'custom/swiper)
:config
(general-unbind 'global "C-s")
:custom
(swiper-include-line-number-in-search t)
:custom-face (swiper-match-face-1 ((t (:background "#dddddd"))))
:custom-face (swiper-match-face-2 ((t (:background "#bbbbbb" :weight bold))))
:custom-face (swiper-match-face-3 ((t (:background "#bbbbff" :weight bold))))
:custom-face (swiper-match-face-4 ((t (:background "#ffbbff" :weight bold)))))
(use-package avy
:ensure t
:general
("C-:" 'avy-goto-char)
("M-s M-s" 'avy-goto-word-0)
:custom
(avy-timeout-seconds 0.5)
(avy-keys '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
:custom-face (avy-goto-char-timer-face ((nil (:foreground "green" :weight bold))))
:config
(avy-setup-default))
(use-package filecache)
(use-package ialign
:ensure t
:general
(:keymaps 'ctl-x-map
"l" 'ialign))
(use-package multiple-cursors
:ensure t
:general
(:keymaps 'region-bindings-mode-map
"C-*" 'mc/mark-all-like-this
"C-S-<up>" 'mc/mark-previous-like-this
"C-S-<down>" 'mc/mark-next-like-this
"C-%" 'mc/mark-more-like-this-extended))
(use-package delsel
:general
(:keymaps 'mode-specific-map
"C-g" 'minibuffer-keyboard-quit)
:config
(delete-selection-mode 1))
;;TODO: bind to keys more extensively
;;TODO: consolidate (un)filling functionality
(use-package unfill
:ensure t
:general
([remap fill-paragraph] 'unfill-toggle))
(use-package simple
:hook
(((prog-mode-hook text-mode-hook) . turn-on-auto-fill))
:delight
((visual-line-mode . " ↩")
(auto-fill-function . " ↵"))
:preface
(defun custom/newline-hook ()
(local-set-key (kbd "C-m") 'newline-and-indent)
(local-set-key (kbd "<return>") 'newline-and-indent))
(defun custom/gnocchi-case (s)
"Convert S to 'gnocchi case'."
(declare (side-effect-free t))
(s-join " " (mapcar 'downcase (s-split-words s))))
(defun custom/switch-case (&optional style)
(interactive)
(let* ((bounds (bounds-of-thing-at-point 'symbol))
(from (if (use-region-p) (region-beginning) (car bounds)))
(to (if (use-region-p) (region-end) (cdr bounds)))
(data (buffer-substring-no-properties from to))
(result (funcall (cond ((eq style 'camel) 's-lower-camel-case)
((eq style 'camel-up) 's-upper-camel-case)
((eq style 'snake) 's-snake-case)
((eq style 'gnocchi) 'custom/gnocchi-case)
((eq style 'kebab) 's-dashed-words)
(t 's-lower-camel-case))
data)))
(save-excursion
(delete-region from to)
(goto-char from)
(insert result))))
:hook (((yaml-mode-hook emacs-lisp-mode-hook lisp-mode-hook python-mode-hook) . custom/newline-hook))
:general
("M-g" 'goto-line)
("M-SPC" 'cycle-spacing)
(:prefix "<f11>"
"b" 'subword-mode
"v" 'view-mode)
(:prefix "C-z"
"o" 'just-one-space
"w" 'delete-trailing-whitespace
"s" 'transpose-sexps
"6" '(lambda () (interactive) (custom/switch-case 'camel))
"^" '(lambda () (interactive) (custom/switch-case 'camel-up))
"_" '(lambda () (interactive) (custom/switch-case 'snake))
"SPC" '(lambda () (interactive) (custom/switch-case 'gnocchi))
"-" '(lambda () (interactive) (custom/switch-case 'kebab)))
:custom
(bidi-display-reordering nil)
(kill-whole-line t)
(next-line-add-newlines nil)
(blink-matching-paren nil)
(set-mark-command-repeat-pop nil)
(save-interprogram-paste-before-kill t)
(x-gtk-use-system-tooltips nil)
(eval-expression-print-length nil)
(eval-expression-print-level nil)
(kill-ring-max 1024)
:config
(general-unbind 'global "<f11>" "C-z")
(column-number-mode 1)
(line-number-mode 1)
(size-indication-mode 1)
(toggle-truncate-lines 1)
(transient-mark-mode 1)
(put 'transient-mark-mode 'permanent-local t)
(put 'set-goal-column 'disabled nil))
(use-package tabify
:general
(:keymaps 'mode-specific-map
"t SPC" 'untabify
"t TAB" 'tabify))
(use-package sort
:general
(:keymaps 'mode-specific-map
"s s" 'sort-lines
"s u" 'delete-duplicate-lines))
(use-package easy-kill
:ensure t
:general
([remap kill-ring-save] 'easy-kill)
([remap mark-sexp] 'easy-mark))
(use-package region-bindings-mode
:ensure t
:custom
(region-bindings-mode-disable-predicates '((lambda () buffer-read-only)))
:config
(region-bindings-mode-enable))
(use-package recursive-narrow
:ensure t
:general
(:keymaps 'mode-specific-map
"n r" 'narrow-to-region
"n d" 'narrow-to-defun
"n w" 'widen
"n N" 'recursive-narrow-or-widen-dwim
"n D" 'recursive-widen-dwim))
(use-package highlight-indent-guides
:ensure t
:general
(:keymaps 'mode-specific-map
"g h" 'highlight-indent-guides-mode)
:custom
(highlight-indent-guides-method 'fill)
(highlight-indent-guides-responsive 'stack))
(use-package comment-dwim-2
:ensure t
:general
(:keymaps 'mode-specific-map
"]" 'comment-dwim-2))
(use-package newcomment
:general
(:keymaps 'mode-specific-map
"/" 'comment-box))
(use-package savekill :ensure t)
(use-package copy-as-format
:ensure t
:general
(:keymaps 'mode-specific-map
"f s" 'copy-as-format-slack
"f g" 'copy-as-format-github
"f o" 'copy-as-format-org-mode
"f m" 'copy-as-format-markdown
"f a" 'copy-as-format-asciidoc
"f b" 'copy-as-format-bitbucket
"f d" 'copy-as-format-disqus
"f l" 'copy-as-format-gitlab
"f c" 'copy-as-format-hipchat
"f h" 'copy-as-format-html
"f j" 'copy-as-format-jira
"f w" 'copy-as-format-mediawiki
"f p" 'copy-as-format-pod
"f r" 'copy-as-format-rst
"f f" 'copy-as-format))
(use-package select
:custom
(select-enable-clipboard t)
(x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))
(use-package undo-propose
:ensure t
:general
(:keymaps 'ctl-x-map
"u" 'undo-propose))
(use-package flycheck
:ensure t
:preface
;; CREDITS: https://github.com/nathankot/dotemacs
(defvar counsel-flycheck-history nil
"History for `counsel-flycheck'")
(defun counsel-flycheck ()
(interactive)
(if (not (bound-and-true-p flycheck-mode))
(message "Flycheck mode is not available or enabled")
(ivy-read "Error: "
(let ((source-buffer (current-buffer)))
(with-current-buffer (or (get-buffer flycheck-error-list-buffer)
(progn
(with-current-buffer
(get-buffer-create flycheck-error-list-buffer)
(flycheck-error-list-mode)
(current-buffer))))
(flycheck-error-list-set-source source-buffer)
(flycheck-error-list-reset-filter)
(revert-buffer t t t)
(split-string (buffer-string) "\n" t " *")))
:action (lambda (s &rest _)
(-when-let* ( (error (get-text-property 0 'tabulated-list-id s))
(pos (flycheck-error-pos error)) )
(goto-char (flycheck-error-pos error))))
:history 'counsel-flycheck-history)))
:general
(:keymaps 'mode-specific-map
"y" 'counsel-flycheck)
:custom-face (flycheck-warning ((t (:foreground "yellow" :background "red"))))
:custom
(flycheck-check-syntax-automatically '(mode-enabled save idle-change))
(flycheck-display-errors-delay 0.4)
(flycheck-display-errors-function #'flycheck-display-error-messages-unless-error-list)
(flycheck-global-modes '(not emacs-lisp-mode))
:config
(global-flycheck-mode 1))
(use-package flycheck-pos-tip
:ensure t
:after (flycheck)
:config
(flycheck-pos-tip-mode 1))
(use-package executable
:hook (after-save-hook . executable-make-buffer-file-executable-if-script-p))
(use-package text-mode
:hook (text-mode-hook . text-mode-hook-identify))
(use-package jka-cmpr-hook
:config
(auto-compression-mode 1))
(use-package electric
:config
(electric-indent-mode -1))
(use-package persistent-scratch
:ensure t
:mode ("^*scratch*$" . lisp-interaction-mode)
:hook ((after-init-hook . persistent-scratch-restore)
(kill-emacs-hook . persistent-scratch-save)))
(use-package yatemplate
:ensure t
:after (yasnippet)
:init
(auto-insert-mode)
:custom
(yatemplate-dir (at-config-basedir "resources/auto-insert"))
:config
(yatemplate-fill-alist))
(use-package editorconfig
:ensure t
:delight (editorconfig-mode " EC")
:hook ((prog-mode-hook text-mode-hook) . editorconfig-mode))
(use-package autorevert
:defer 2
:custom
(auto-revert-verbose nil)
(global-auto-revert-non-file-buffers t)
(auto-revert-check-vc-info t)
;; (vc-handled-backends (delq 'Git vc-handled-backends))
;; (vc-handled-backends nil)
:config
(global-auto-revert-mode 1))
(use-package kmacro
:custom
(setq kmacro-ring-max 16))
(use-package mwheel
:custom
(mouse-wheel-scroll-amount '(1 ((shift) . 1)))
(mouse-wheel-progressive-speed nil))
(use-package whitespace
:ensure t
:defer 2
:hook
((prog-mode-hook text-mode-hook) . whitespace-turn-on)
:general
(:keymaps 'mode-specific-map
"x w" 'whitespace-mode
"x W" 'global-whitespace-mode)
:custom
(whitespace-line-column 121)
(whitespace-style '(indentation::space
space-after-tab
space-before-tab
trailing
lines-tail
tab-mark
face
tabs)))
;;TODO: consolidate all whitespaces utils
;;TODO: think of activating ws-butler in some modes, just for hands-on testing
(use-package ws-butler
:ensure t
:commands ws-butler-mode)
(use-package rst
:mode ("\\.rst$" . rst-mode))
(use-package vimrc-mode
:ensure t
:mode ((".vim\\(rc\\)?$" . vimrc-mode)
("*pentadactyl*" . vimrc-mode)))
(use-package sh-script
:mode (("bashrc$" . shell-script-mode)
("bash_profile$" . shell-script-mode)
("bash_aliases$" . shell-script-mode)
("bash_local$" . shell-script-mode)
("bash_completion$" . shell-script-mode)
(".powenv$" . shell-script-mode)
("\\zsh\\'" . shell-script-mode))
:config
;; zsh
(setq system-uses-terminfo nil))
(use-package nginx-mode
:ensure t
:mode ("nginx" . nginx-mode))
(use-package fic-mode :ensure t)
(use-package csv-mode
:ensure t
:mode ("\\.csv" . csv-mode)
:config
(setq-default csv-align-padding 2))
(use-package jinja2-mode
:ensure t
:mode ("\\.j2$" . jinja2-mode))
(use-package yaml-mode
:ensure t
:mode (("\\.yml\\'" . yaml-mode)
("\\.yaml\\'" . yaml-mode)))
(use-package dockerfile-mode
:ensure t
:mode ("\\Dockerfile" . dockerfile-mode))
(use-package docker-compose-mode
:ensure t
:mode ("docker-compose" . docker-compose-mode))
(use-package smartparens
:ensure t
:after (dash)
:demand t
:hook (((prog-mode-hook yaml-mode-hook) . smartparens-mode)
((lisp-mode-hook emacs-lisp-mode-hook markdown-mode-hook) . smartparens-strict-mode))
:general
(:keymaps 'smartparens-mode-map
;;TODO: try to make more brief keybindings
"C-M-t" 'sp-transpose-sexp
"M-F" nil
"M-B" nil
"M-<backspace>" nil
"C-S-a" 'sp-beginning-of-sexp
"C-S-d" 'sp-end-of-sexp
")" 'sp-up-sex
"C-<left_bracket>" 'sp-select-previous-thing)
:config
(use-package smartparens-config)
(show-smartparens-global-mode t)
(sp-use-smartparens-bindings))
(use-package paren
:defer 2
:custom
(show-paren-delay 0)
:config
(show-paren-mode t))
(use-package dtrt-indent
:ensure t
:config
(dtrt-indent-mode))
(use-package aggressive-indent
:ensure t
:if enable-experimental-packages
:config
(global-aggressive-indent-mode 1)
(add-to-list 'aggressive-indent-excluded-modes 'html-mode)
(add-to-list 'aggressive-indent-excluded-modes 'slime-repl-mode)
(add-to-list 'aggressive-indent-excluded-modes 'haskell-mode)
(add-to-list 'aggressive-indent-excluded-modes 'lisp-mode)
(add-to-list 'aggressive-indent-excluded-modes 'emacs-lisp-mode)
(delete 'lisp-mode aggressive-indent-modes-to-prefer-defun)
(delete 'emacs-lisp-mode aggressive-indent-modes-to-prefer-defun)
(add-to-list 'aggressive-indent-dont-indent-if
'(not (null (string-match (rx (zero-or-more space) (syntax comment-start) (zero-or-more anything)) (thing-at-point 'line))))))
(use-package dynamic-ruler
:ensure t
:general
("C->" 'dynamic-ruler)
("C-^" 'dynamic-ruler-vertical))
(use-package yasnippet ;;TODO: make more declarative
:ensure t
:demand t
:delight yas-minor-mode
:mode (("yasnippet/snippets" . snippet-mode)
("\\.yasnippet$" . snippet-mode))
:preface
;; hook for automatic reloading of changed snippets
(defun custom/update-yasnippets-on-save ()
(when (string-match "/resources/yasnippet" buffer-file-name)
(yas-load-directory (at-config-basedir "resources/"))))
;; Inter-field navigation
(defun custom/yas-goto-end-of-active-field ()
(interactive)
(let* ((snippet (car (yas--snippets-at-point)))
(position (yas--field-end (yas--snippet-active-field snippet))))
(if (= (point) position)
(move-end-of-line)
(goto-char position))))
(defun custom/yas-goto-start-of-active-field ()
(interactive)
(let* ((snippet (car (yas--snippets-at-point)))
(position (yas--field-start (yas--snippet-active-field snippet))))
(if (= (point) position)
(move-beginning-of-line)
(goto-char position))))
(defun custom/do-yas-expand ()
(let ((yas/fallback-behavior 'return-nil))
(yas/expand)))
(defun custom/tab-indent-or-complete ()
(interactive)
(if (minibufferp)
(minibuffer-complete)
(if (or (not yas/minor-mode)
(null (custom/do-yas-expand)))
(if (check-expansion)
(company-complete-common)
(indent-for-tab-command)))))
:general
(:prefix "<f5>"
"v" 'yas-visit-snippet-file
"i" 'ivy-yasnippet)
(:keymaps 'yas-keymap
[(tab)] nil
[(shift tab)] nil
[backtab] nil
"TAB" nil
"<return>" 'yas-exit-all-snippets
"C-e" 'custom/yas-goto-end-of-active-field
"C-a" 'custom/yas-goto-start-of-active-field
"C-n" 'yas-next-field-or-maybe-expand
"C-p" 'yas-prev-field)
(:keymaps 'yas-minor-mode-map
[(tab)] nil
"<tab>" nil
"TAB" nil)
:hook
(hippie-expand-try-functions-list . yas-hippie-try-expand)
(after-save-hook . custom/update-yasnippets-on-save)
:config
;; snippets editing mode
(use-package ivy-yasnippet
:after (dash ivy yasnippet)
:ensure t)
(setq yas-snippet-dirs nil)
(push yas-installed-snippets-dir yas-snippet-dirs)
(push (at-config-basedir "resources/yasnippet/") yas-snippet-dirs)
(push (at-config-basedir "resources/yasnippet-private/") yas-snippet-dirs)
(setq yas-key-syntaxes '("w" "w_" "w_." "^ " "w_.()" yas-try-key-from-whitespace))
(setq yas-expand-only-for-last-commands '(self-insert-command))
(setq yas-prompt-functions
'(yas-completing-prompt
yas-x-prompt
yas-no-prompt))
;; Wrap around region
(setq yas-wrap-around-region t)
(yas-global-mode 1))
(use-package company
:ensure t
:demand t
:delight (company-mode " γ")
:general
(:keymaps 'company-active-map
"C-n" 'company-select-next
"C-p" 'company-select-previous
"C-d" 'company-show-doc-buffer
"M-." 'company-show-location)
:custom
(company-idle-delay 0)
(company-minimum-prefix-length 2)
(company-tooltip-align-annotations t)
(company-show-numbers t)
:config
(use-package company-flx
:ensure t
:no-require t
:after (company)
:config
(company-flx-mode +1))
(use-package company-quickhelp
:ensure t
:no-require t
:after (company)
:general
(:keymaps 'company-active-map
"C-c h" 'company-quickhelp-manual-begin)
:config
(company-quickhelp-mode 1))
(use-package company-statistics
:ensure t
:after (company)
:config
(company-statistics-mode))
(global-company-mode))
(use-package company-ansible
:ensure t
:after (company)
:config
(add-to-list 'company-backends 'company-ansible))
(use-package poly-ansible
:ensure t)
(use-package hippie-exp
:general
("C-S-<iso-lefttab>" 'hippie-expand)
:custom
(setq hippie-expand-try-functions-list
'(yas-hippie-try-expand
try-expand-all-abbrevs
try-complete-file-name-partially
try-complete-file-name
try-expand-dabbrev
try-expand-dabbrev-from-kill
try-expand-dabbrev-all-buffers
try-expand-list
try-expand-line
try-complete-lisp-symbol-partially
try-complete-lisp-symbol)))
(use-package abbrev
:delight (abbrev-mode " Abv")
:config
(setq-default abbrev-mode t))
(use-package docker
:ensure t
:after (dash docker-tramp s tablist json-mode)
:delight docker-mode
:custom
(docker-containers-show-all t)
:config
;;TODO: bind keys
;;FIXME: epkgs.docker is something another then the original - investigate this
(docker-global-mode 1))
(use-package docker-tramp :ensure t)
(use-package vagrant-tramp :ensure t)
;;TODO: rebind to something
(use-package counsel-tramp
:ensure t
:after (docker-tramp vagrant-tramp))
(use-package eldoc
:delight eldoc-mode
:hook ((emacs-lisp-mode-hook lisp-interaction-mode-hook ielm-mode-hook) . turn-on-eldoc-mode)
:custom
(eldoc-idle-delay 0))
(use-package c-eldoc
:ensure t
:after (eldoc)
:hook ((c-mode-hook c++-mode-hook) . c-turn-on-eldoc-mode))
(use-package eldoc-eval
:ensure t
:after (eldoc))
;;TODO: extend setup
(use-package compile)
(use-package multi-compile :ensure t)
(use-package regex-tool
:ensure t
:commands regex-tool
:custom
(regex-tool-backend 'perl))
(use-package xr
:ensure t)
(use-package prog-fill
:ensure t
:general
(:keymaps 'prog-mode-map
"M-q" 'prog-fill))
(use-package ini-mode
:ensure t
:mode ("\\.ini\\'" . ini-mode))
(use-package po-mode
:ensure t
:mode ("\\.po$\\|\\.po\\." . po-mode))
(use-package diff-mode
:mode ("diff" . diff-mode))
(use-package make-mode
:mode ("[Mm]akefile" . makefile-mode))
;; TODO: (alex3rd) extend setup
(use-package format-all :ensure t)
(use-package skeletor
:ensure t
:custom
(skeletor-project-directory (at-workspace-dir "pets")))
(use-package lsp-mode
:ensure t
:hook (lsp-after-open-hook . lsp-enable-imenu)
:custom
(lsp-message-project-root-warning t)
(lsp-inhibit-message t)
(lsp-prefer-flymake nil)
:config
(use-package lsp-clients))
(use-package lsp-ui
:ensure t
:after (lsp-mode)
:hook (lsp-mode-hook . lsp-ui-mode)
:general
(:keymaps 'lsp-ui-mode-map
[remap xref-find-definitions] 'lsp-ui-peek-find-definitions
[remap xref-find-references] 'lsp-ui-peek-find-references)
(:keymaps 'mode-specific-map
"R" 'lsp-restart-workspace))
(use-package company-lsp
:ensure t
:custom
(company-lsp-cache-candidates 'auto)
(company-lsp-async t)
(company-lsp-enable-recompletion t)
:config
(push 'company-lsp company-backends))
(use-package magit
:ensure t
:after (async dash with-editor git-commit magit-popup)
:commands magit-status magit-blame
:mode (("COMMIT_EDITMSG" . conf-javaprop-mode)
("COMMIT" . git-commit-mode))
:general
(:prefix "C-'"
"s" 'magit-status
"f" 'magit-log-buffer-file
"c" 'magit-checkout
"w" 'magit-diff-working-tree
"r" 'magit-reflog
"b" 'magit-blame-addition
"B" 'magit-branch-manager
"l" 'magit-log
"l" 'open-global-repos-list)
(:keymaps 'magit-status-mode-map
"E" 'magit-rebase-interactive
"q" 'custom/magit-kill-buffers)
:preface
(defun open-global-repos-list ()
(interactive)
(let ((repos-buffer (get-buffer "*Magit Repositories*")))
(if repos-buffer
(switch-to-buffer repos-buffer)
(magit-list-repositories))))
(defun custom/magit-restore-window-configuration (&optional kill-buffer)
"Bury or kill the current buffer and restore previous window configuration."
(let ((winconf magit-previous-window-configuration)
(buffer (current-buffer))
(frame (selected-frame)))
(quit-window kill-buffer (selected-window))
(when (and winconf (equal frame (window-configuration-frame winconf)))
(set-window-configuration winconf)
(when (buffer-live-p buffer)
(with-current-buffer buffer
(setq magit-previous-window-configuration nil))))))
(defun custom/magit-kill-buffers ()
"Restore window configuration and kill all Magit buffers."
(interactive)
(let ((buffers (magit-mode-get-buffers)))
(magit-restore-window-configuration)
(mapc #'kill-buffer buffers)))
:custom
(magit-completing-read-function 'ivy-completing-read)
(magit-blame-heading-format "%H %-20a %C %s")
(magit-diff-refine-hunk t)
(magit-display-buffer-function 'magit-display-buffer-fullframe-status-topleft-v1)
(magit-repository-directories private/magit-repositories)
:config
(use-package magit-filenotify
:ensure t
:delight (magit-filenotify-mode " FN")
:after magit
:hook (magit-status-mode-hook . (lambda ()
(condition-case nil
(magit-filenotify-mode)
(error (magit-filenotify-mode -1))))))
(use-package vdiff-magit
:ensure t
:general
(:keymaps 'magit-mode-map
"d" 'vdiff-magit-dwim
"p" 'vdiff-magit-popup)
:config
(setcdr (assoc ?e (plist-get magit-dispatch-popup :actions))
'("vdiff dwim" 'vdiff-magit-dwim))
(setcdr (assoc ?E (plist-get magit-dispatch-popup :actions))
'("vdiff popup" 'vdiff-magit-popup))))
(use-package magithub
:disabled
:ensure t
:after (magit)
:custom
(magithub-clone-default-directory (at-workspace-dir "foss"))
:config
(magithub-feature-autoinject t))
(use-package git-timemachine
:ensure t
:after (ivy)
:demand t
:preface
;; credits to @binchen
(defun custom/git-timemachine-show-selected-revision ()
"Show last (current) revision of file."
(interactive)
(let* ((collection (mapcar (lambda (rev)
;; re-shape list for the ivy-read
(cons (concat (substring-no-properties (nth 0 rev) 0 7) "|" (nth 5 rev) "|" (nth 6 rev)) rev))
(git-timemachine--revisions))))
(ivy-read "commits:"
collection
:action (lambda (rev)
;; compatible with ivy 9+ and ivy 8
(unless (string-match-p "^[a-z0-9]*$" (car rev))
(setq rev (cdr rev)))
(git-timemachine-show-revision rev))
:unwind (lambda () (if (not (eq last-command-event 13))
(git-timemachine-quit))))))
(defun custom/git-timemachine ()
"Open git snapshot with the selected version. Based on ivy-mode."
(interactive)
(git-timemachine--start #'custom/git-timemachine-show-selected-revision))
:general
(:keymaps 'mode-specific-map
";" 'custom/git-timemachine))
(use-package gitignore-mode
:ensure t
:mode ("^.gitignore$" . gitignore-mode))
;; think of relocating, cause it supports not only Git
(use-package diff-hl
:ensure t
:hook (magit-post-refresh-hook . diff-hl-magit-post-refresh)
:config
(global-diff-hl-mode 1))
(use-package git-msg-prefix
:ensure t
:general
(:keymaps 'git-commit-mode-map
"C-c i" 'commit-msg-prefix)
:custom
(git-msg-prefix-log-flags " --since='1 week ago' ")
(commit-msg-prefix-input-method 'ivy-read))
(use-package browse-at-remote
:ensure t
:general
(:keymaps 'mode-specific-map
"g g" 'browse-at-remote)
(:keymaps 'magit-status-mode-map
"o" 'browse-at-remote)
:custom
(browse-at-remote-prefer-symbolic nil))
BACKLOG [#A] find some way (maybe smth like spacemacs dashboard) to represent the states of repos from some list (either hardcoded or created dynamically), with unstaged/unpushed/whatever_useful info displayed
(use-package smerge-mode
:delight (smerge-mode "∓")
:general
(:keymaps 'mode-specific-map
"g k" 'smerge-prev
"g j" 'smerge-next)
(:keymaps 'local
:predicate '(bound-and-true-p smerge-mode)
"n" 'smerge-next
"p" 'smerge-prev
"b" 'smerge-keep-base
"u" 'smerge-keep-upper
"l" 'smerge-keep-lower
"a" 'smerge-keep-all
"RET" 'smerge-keep-current
"C-m" 'smerge-keep-current
"<" 'smerge-diff-base-upper
"=" 'smerge-diff-upper-lower
">" 'smerge-diff-base-lower
"R" 'smerge-refine
"E" 'smerge-ediff
"C" 'smerge-combine-with-next
"r" 'smerge-resolve
"k" 'smerge-kill-current
"ZZ" '(lambda ()
(interactive)
(save-buffer)
(bury-buffer)))
:hook (find-file-hooks . (lambda ()
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^<<<<<<< " nil t)
(smerge-mode 1))))))
(use-package info-look)
(use-package edebug-x :ensure t)
(use-package elisp-slime-nav
:delight elisp-slime-nav-mode
:ensure t
:hook ((emacs-lisp-mode-hook ielm-mode-hook) . elisp-slime-nav-mode))
(use-package elisp-mode
:hook ((emacs-lisp-mode-hook . (lambda ()
(auto-fill-mode 1)
(setq indent-tabs-mode nil)
(setq comment-start ";;")
(turn-on-eldoc-mode)))))
(use-package company-elisp
:after (elisp-mode company)
:config
(add-to-list 'company-backends 'company-elisp))
(add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)
(dolist (mode '(paredit-mode smartparens-mode))
(when (fboundp mode)
(add-hook 'eval-expression-minibuffer-setup-hook mode)))
(use-package slime
:ensure t
:pin melpa-stable ;; corresponds to quicklisp version
:hook ((lisp-mode-hook . (lambda ()
(slime-mode t)
(set (make-local-variable 'slime-lisp-implementations)
(list (assoc 'sbcl slime-lisp-implementations)))))
(inferior-lisp-mode-hook . inferior-slime-mode)
(slime-mode-hook . (lambda () (when (> emacs-major-version 25)
(slime-autodoc-mode -1)))) ;; some signature down the call stack is broken in 2.20
(lisp-mode-hook . (lambda ()
(auto-fill-mode 1)
(setq indent-tabs-mode nil))))
:init
(use-package slime-autoloads)
:custom
(slime-complete-symbol*-fancy t)
(slime-complete-symbol-function 'slime-fuzzy-complete-symbol)
(slime-net-coding-system 'utf-8-unix)
:config
(defadvice slime-documentation-lookup
(around change-browse-url-browser-function activate)
"Use w3m for slime documentation lookup."
(let ((browse-url-browser-function 'w3m-browse-url))
ad-do-it))
(slime-setup
'(slime-fancy-inspector slime-fancy-trace slime-fontifying-fu
slime-hyperdoc slime-package-fu slime-references slime-trace-dialog
slime-xref-browser slime-asdf slime-autodoc slime-banner slime-fancy
slime-fuzzy slime-repl slime-sbcl-exts))
(add-to-list 'slime-lisp-implementations '(sbcl ("sbcl") :coding-system utf-8-unix)))
;;TODO: check if there is any conflict inconsistency between slime-builtin/company completion
(use-package slime-company
:ensure t
:after (slime company))
(setq custom/hyperspec-root "~/help/HyperSpec/")
(use-package inf-lisp
:config
(setq inferior-lisp-program "sbcl"))
(use-package common-lisp-snippets
:ensure t
:after (yasnippet))
;; lookup information in hyperspec
(info-lookup-add-help
:mode 'lisp-mode
:regexp "[^][()'\" \t\n]+"
:ignore-case t
:doc-spec '(("(ansicl)Symbol Index" nil nil nil)))
(use-package python
:mode ("\\.py$" . python-mode)
:hook
(python-mode-hook . (lambda ()
(setq indent-tabs-mode nil)
(setq tab-width 4)
(setq imenu-create-index-function 'imenu-default-create-index-function)
(auto-fill-mode 1)))
;; Highlight the call to ipdb, src http://pedrokroger.com/2010/07/configuring-emacs-as-a-python-ide-2/
(python-mode-hook . (lambda ()
(highlight-lines-matching-regexp "import ipdb")
(highlight-lines-matching-regexp "ipdb.set_trace()")
(highlight-lines-matching-regexp "import wdb")
(highlight-lines-matching-regexp "wdb.set_trace()")))
(python-mode-hook . lsp)
(python-mode-hook . flycheck-mode)
:general
(:keymaps 'python-mode-map
"M-_" 'python-indent-shift-left
"M-+" 'python-indent-shift-right)
:config
(add-function :before-until (local 'eldoc-documentation-function)
#'(lambda () "")))
(use-package py-yapf :ensure t)
(use-package pyvenv
:ensure t
:after (projectile dash)
:init
(defun custom/switch-python-project-context ()
(let ((project-root (projectile-project-root)))
(when (-non-nil (mapcar (lambda (variant) (file-exists-p (concat project-root variant)))
'("requirements.pip" "requirements.txt")))
(pyvenv-deactivate)
(pyvenv-activate (format "%s/%s"
(pyvenv-workon-home)
(file-name-base
(directory-file-name
project-root)))))))
:config
(pyvenv-mode 1)
:hook ((projectile-after-switch-project-hook . custom/switch-python-project-context)
(python-mode . custom/switch-python-project-context)))
(use-package pip-requirements
:ensure t
:delight (pip-requirements-mode "PyPA Requirements")
:preface
(defun custom/pip-requirements-ignore-case ()
(setq-local completion-ignore-case t))
:mode ("requirements\\." . pip-requirements-mode)
:hook (pip-requirements-mode . custom/pip-requirements-ignore-case))
;;TODO: some harness either here or withoin shell to automate the burden of setting up new golang project's boilerplate
(use-package go-mode
:ensure t
:no-require t
:after (multi-compile)
:mode ("\\.go$" . go-mode)
:hook (before-save-hook . gofmt-before-save)
:general
(:keymaps 'go-mode-map
"C-c C-c" 'multi-compile-run
"M-." 'godef-jump
"M-," 'pop-tag-mark)
:config
(use-package godoctor :ensure t)
(setq gofmt-command "goimports")
(add-to-list 'multi-compile-alist
'(go-mode . (("go-build/git" "go build -v"
(locate-dominating-file buffer-file-name ".git")) ;;TODO: try to guess binary name from project name (investigate how this refers to libraries builds, etc.)
("go-build/main" "go build -v"
(locate-dominating-file buffer-file-name "main.go"))
("go-build-and-run/git" "go build -v && echo '########## build finished ##########' && eval ./${PWD##*/}"
(multi-compile-locate-file-dir ".git"))
("go-build-and-run/main" "go build -v && echo '########## build finished ##########' && eval ./${PWD##*/}"
(multi-compile-locate-file-dir "main.go"))))))
(use-package company-go
:ensure t
:after (go-mode company)
:config
(add-to-list 'company-backends 'company-go))
(use-package go-guru
:ensure t
:hook (go-mode-hook . go-guru-hl-identifier-mode))
(use-package flycheck-gometalinter
:ensure t
:custom
;; only run fast linters
(flycheck-gometalinter-fast t)
;; use in tests files
(flycheck-gometalinter-test t)
(flycheck-gometalinter-deadline "10s")
;; gometalinter: skips 'vendor' directories and sets GO15VENDOREXPERIMENT=1
(flycheck-gometalinter-vendor t)
;; gometalinter: only enable selected linters
(flycheck-gometalinter-disable-all t)
(flycheck-gometalinter-enable-linters
'("golint" "vet" "vetshadow" "golint" "ineffassign" "goconst" "errcheck" "deadcode"))
:config
(flycheck-gometalinter-setup))
(use-package go-eldoc
:ensure t
:hook (go-mode-hook . go-eldoc-setup))
(use-package gotest
:ensure t
:after (go-mode)
:general
(:keymaps 'go-mode-map
"C-c C-x f" 'go-test-current-file
"C-c C-x t" 'go-test-current-test
"C-c C-x p" 'go-test-current-project
"C-c C-x T" 'go-test-current-benchmark
"C-c C-x F" 'go-test-current-file-benchmarks
"C-c C-x P" 'go-test-current-project-benchmarks
"C-c C-x x" 'go-run))
(use-package go-tag
:ensure t
:no-require t
:after (go-mode)
:general
(:keymaps 'go-mode-map
"C-c t" 'go-tag-add
"C-c T" 'go-tag-remove)
:custom
(go-tag-args '("-transform" "camelcase")))
(use-package go-playground
:ensure t
:after (go-mode))
(use-package gorepl-mode
:ensure t
:hook (go-mode-hook . gorepl-mode))
BACKLOG try to integrate https://getgb.io/
(use-package lua-mode
:ensure t
:preface
(defun lua-broken-indentation-fix ()
(save-excursion
(lua-forward-line-skip-blanks 'back)
(let* ((current-indentation (current-indentation))
(line (thing-at-point 'line t))
(busted-p (s-matches?
(rx (+ bol (* space)
(or "context" "describe" "it" "setup" "teardown")
"("))
line)))
(when busted-p
(+ current-indentation lua-indent-level)))))
(defun rgc-lua-calculate-indentation-override (old-function &rest arguments)
(or (lua-broken-indentation-fix)
(apply old-function arguments)))
:mode ("\\.lua$" . lua-mode)
:hook (lua-mode-hook . (lambda ()
(setq flycheck-checker 'lua-luacheck)))
:config
(advice-add #'lua-calculate-indentation-override
:around #'rgc-lua-calculate-indentation-override))
(use-package company-lua
:ensure t
:after (lua-mode company))
(use-package nix-mode
:ensure t
:mode (("\\.nix$" . nix-mode)
((rx (eval "configuration.nix") (zero-or-more anything) eol) . nix-mode)))
(use-package company-nixos-options
:ensure t
:disabled
:config
(add-to-list 'company-backends 'company-nixos-options))
(use-package rustic
:ensure t
:hook (rust-mode-hook . lsp)
:custom (rustic-rls-pkg 'lsp-mode)
:mode ("\\.rs" . rustic-mode))
(use-package clojure-mode
:defer t
:config
(define-clojure-indent
(alet 'defun)
(mlet 'defun)))
(use-package clojure-snippets
:defer t)
(use-package cider
:defer t
;; :custom
;; (cider-repl-display-help-banner nil)
:config
;; sadly, we can't use :diminish keyword here, yet
(diminish 'cider-mode
'(:eval (format " 🍏%s" (cider--modeline-info)))))
(use-package kibit-helper
:disabled ;;TODO: setup kibit first
:defer t)
(use-package actionscript-mode
:ensure t
:mode ("\\.actionscript" . actionscript-mode))
(use-package json-mode
:after (json-reformat json-snatcher)
:mode ("\\.json$" . json-mode))
(use-package opascal
:quelpa
(opascal :repo "ki11men0w/emacs-delphi-mode" :fetcher github)
:mode ("\\.\\(pas\\|dpr\\|dpk\\)\\'" . opascal-mode)
:preface
(defun custom/enclose-by-spaces (left right)
"Insert symbols LEFT and RIGHT around a region or point."
(interactive "r")
(if (use-region-p) ; act on region
(let ((start (region-beginning))
(end (region-end)))
(save-excursion
(goto-char end)
(insert " ")
(goto-char start)
(insert " ")))
(progn ; act around point
(insert " " " ")
(backward-char 1))))
:general
(:keymaps 'mode-specific-map
"a" 'custom/enclose-by-spaces)
:custom
(opascal-indent-level 2)
:config
(smartparens-mode -1))
(use-package ccls
:ensure t
:after (lsp-mode)
:hook ((c-mode-hook c++-mode-hook objc-mode-hook) . (lambda () (require 'ccls) (lsp)))
:custom
(ccls-executable "/run/current-system/sw/bin/ccls")
:config
(setq-default flycheck-disabled-checkers '(c/c++-clang c/c++-cppcheck c/c++-gcc)))
(use-package sgml-mode
:general
(:keymaps 'html-mode-map
"C-c C-w" 'html-wrap-in-tag))
(use-package markdown-mode
:ensure t
:mode (("\\.markdown$" . markdown-mode)
("\\.md$" . markdown-mode)
("\\.mkd$" . markdown-mode)
("\\.pdc$" . markdown-mode)
("\\.README$" . markdown-mode))
:general
(:keymaps 'markdown-mode-map
"C-c C-v" 'markdown-preview
"C-<tab>" 'yas/expand))
(use-package graphql-mode
:ensure t
:mode ("\\.graphql$" . graphql-mode))
(use-package web-mode
:ensure t
:mode (("\\.phtml\\'" . web-mode)
("\\.tpl\\.php\\'" . web-mode)
("\\.[agj]sp\\'" . web-mode)
("\\.as[cp]x\\'" . web-mode)
("\\.erb\\'" . web-mode)
("\\.mustache\\'" . web-mode)
("\\.djhtml\\'" . web-mode)
("\\.html?\\'" . web-mode))
:general
(:keymaps 'web-mode-map
"M-SPC" 'company-complete) ;; manual autocomplete
:hook (web-mode-hook . (lambda ()
(set (make-local-variable 'company-backends)
'(company-tern company-web-html company-yasnippet company-files))
(company-mode t)))
:custom
(web-mode-enable-current-element-highlight t)
(web-mode-enable-auto-closing t)
(web-mode-enable-auto-expanding t)
(web-mode-enable-auto-pairing t)
(web-mode-enable-auto-quoting t)
(web-mode-enable-css-colorization t)
(web-mode-markup-indent-offset 2)
(web-mode-code-indent-offset 2)
(web-mode-css-indent-offset 2)
:config
(use-package company-web
:ensure t
:after (company dash web-completion-data))
(use-package web-mode-edit-element
:ensure t
:hook (web-mode-hook . web-mode-edit-element-minor-mode))
(use-package web-narrow-mode
:ensure t
:hook (web-mode-hook . web-narrow-mode))
(add-to-list 'web-mode-engines-alist '("django" . "\\.html\\'"))
;; Enable JavaScript completion between <script>...</script> etc.
;; TODO: check why company and AC are mentioned together (see below)
(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)))))))
(use-package css-mode
:mode ("\\.scss$" . css-mode))
(use-package css-eldoc
:ensure t
:after (eldoc)
:hook (css-mode-hook . turn-on-css-eldoc))
(use-package rainbow-mode
:ensure t
:hook (css-mode-hook . rainbow-mode))
(use-package emmet-mode
:ensure t
:delight emmet-mode
:commands emmet-mode
:general
(:keymaps 'emmet-mode-keymap
"C-j" nil
"<C-return>" nil
"C-c C-j" 'emmet-expand-line)
:hook ((sgml-mode-hook nxml-mode-hook django-mode sgml-mode-hook css-mode-hook) . emmet-mode)
:custom
(emmet-move-cursor-between-quotes t)
(emmet-indentation 2))
(use-package company-restclient
:ensure t
:after (restclient company))
(use-package ob-restclient
:ensure t
:after (ob restclient)
:commands (org-babel-execute:restclient))
(use-package httprepl :ensure t)
(use-package emamux
:ensure t
:general
(:prefix "<f12>"
"n" 'emamux:new-window
"s" 'emamux:send-region
"r" 'emamux:run-command))
(use-package w3m
:ensure t
:commands w3m
:hook (w3m-display-hook . (lambda (url)
(rename-buffer
(format "*w3m: %s*" (or w3m-current-title
w3m-current-url)) t)))
:custom
(w3m-coding-system 'utf-8)
(w3m-file-coding-system 'utf-8)
(w3m-file-name-coding-system 'utf-8)
(w3m-input-coding-system 'utf-8)
(w3m-output-coding-system 'utf-8)
(w3m-terminal-coding-system 'utf-8)
(w3m-use-cookies t)
:config
;; special chars
(standard-display-ascii ?\200 [15])
(standard-display-ascii ?\201 [21])
(standard-display-ascii ?\202 [24])
(standard-display-ascii ?\203 [13])
(standard-display-ascii ?\204 [22])
(standard-display-ascii ?\205 [25])
(standard-display-ascii ?\206 [12])
(standard-display-ascii ?\210 [23])
(standard-display-ascii ?\211 [14])
(standard-display-ascii ?\212 [18])
(standard-display-ascii ?\214 [11])
(standard-display-ascii ?\222 [?\'])
(standard-display-ascii ?\223 [?\"])
(standard-display-ascii ?\224 [?\"])
(standard-display-ascii ?\227 " -- "))
(use-package w3m-search
:after (w3m)
:config
(add-to-list 'w3m-search-engine-alist
'("emacs-wiki" "http://www.emacswiki.org/cgi-bin/wiki.pl?search=%s")))
(use-package eww
:preface
(defun eww-more-readable () ;;TODO: add to appropriate hook
"Makes eww more pleasant to use. Run it after eww buffer is loaded."
(interactive)
(setq eww-header-line-format nil) ;; removes page title
(setq mode-line-format nil) ;; removes mode-line
(set-window-margins (get-buffer-window) 20 20) ;; increases size of margins
(redraw-display) ;; apply mode-line changes
(eww-reload 'local))) ;; apply eww-header changes
(use-package pdf-tools
:ensure t
:hook ((pdf-view-mode-hook . (pdf-links-minor-mode
pdf-outline-minor-mode))
(after-init-hook . pdf-tools-install))
:config
(use-package pdf-view
:ensure nil
:mode ("\\.pdf$" . pdf-view-mode)
;; :magic ("%PDF" . pdf-view-mode)
:preface
(defun custom/scroll-other-window (&optional arg)
(interactive "P")
(awhen (ignore-errors (other-window-for-scrolling))
(let* ((buffer (window-buffer it))
(mode (with-current-buffer buffer major-mode)))
(cond
((eq mode 'pdf-view-mode)
(save-selected-window
(select-window it)
(with-current-buffer buffer
(pdf-view-next-page (cond ((eq arg '-) -1)
((numberp arg) arg)
(t 1))))))
(t (scroll-other-window arg))))))
:general
("C-M-v" 'custom/scroll-other-window)
(:keymaps 'pdf-view-mode-map
"C-s" 'isearch-forward
"h" 'pdf-annot-add-highlight-markup-annotation
"t" 'pdf-annot-add-text-annotation
"y" 'pdf-view-kill-ring-save
"D" 'pdf-annot-delete)
:hook ((after-init-hook . pdf-tools-install)
(pdf-view-mode-hook . pdf-isearch-minor-mode)
;; (pdf-tools-enabled-hook . pdf-view-midnight-minor-mode)
(pdf-view-mode-hook . (lambda () (cua-mode -1)))) ;; turn off cua so copy works
:custom
(pdf-view-midnight-colors (quote ("white smoke" . "#002b36"))) ;; more brightness in midnight mode
(pdf-view-resize-factor 1.1) ;; more fine-grained zooming
(pdf-view-display-size 'fit-page))
(use-package pdf-annot
:ensure nil
:general
(:keymaps 'pdf-annot-edit-contents-minor-mode-map
"<return>" 'pdf-annot-edit-contents-commit
"<S-return>" 'newline)
:custom
(pdf-annot-activate-created-annotations t)
:config
(advice-add 'pdf-annot-edit-contents-commit :after 'save-buffer)))
(use-package footnote)
(use-package sendmail
:custom
(mail-specify-envelope-from t)
(mail-envelope-from 'header)
(send-mail-function 'sendmail-send-it))
(use-package message
:hook (message-mode-hook . turn-on-orgtbl)
:custom
(message-sendmail-envelope-from 'header)
(message-kill-buffer-on-exit t))
(use-package notmuch
:ensure t
:no-require t
:commands notmuch
:general
(:keymaps 'notmuch-search-mode-map
"!" '(lambda ()
"toggle unread tag for thread"
(interactive)
(if (member "unread" (notmuch-search-get-tags))
(notmuch-search-tag '("-unread" "-spam"))
(notmuch-search-tag '("+unread"))))
"g" 'notmuch-refresh-this-buffer)
(:keymaps 'notmuch-message-mode-map
"#" 'mml-attach-file)
(:keymaps 'mode-specific-map
"4 n" 'notmuch
"4 N" 'counsel-notmuch)
:hook ((notmuch-hello-refresh-hook . (lambda ()
(if (and (eq (point) (point-min))
(search-forward "Saved searches:" nil t))
(progn
(forward-line)
(widget-forward 1))
(if (eq (widget-type (widget-at)) 'editable-field)
(beginning-of-line)))))
(message-setup-hook . mml-secure-message-sign-pgpmime)) ;; Crypto Settings
:custom
(mm-text-html-renderer 'w3m)
(notmuch-mua-compose-in 'current-window)
(notmuch-identities private/gmail-accounts)
(notmuch-fcc-dirs private/notmuch-fcc-dirs)
(notmuch-search-line-faces '(("unread" . (:foreground "white"))
("deleted" . (:foreground "red" :background "blue"))))
(notmuch-saved-searches private/notmuch-saved-searches)
(notmuch-crypto-process-mime t) ; Automatically check signatures
(notmuch-hello-hide-tags (quote ("killed")))
(notmuch-address-command "notmuch-addrlookup")
:config
(use-package org-notmuch
:after (org notmuch))
(use-package counsel-notmuch
:ensure t
:after (counsel notmuch)
:commands counsel-notmuch))
BACKLOG try tagging from https://asynchronous.in/2017/04/21/Email-with-notmuch-and-astroid/
(use-package pass
:ensure t
:general
(:prefix "<f6>"
"p" 'pass
"!" 'ivy-pass)
:config
(use-package ivy-pass :ensure t))
(imagemagick-register-types)
(use-package wttrin
:ensure t
:after (xterm-color)
:custom
(wttrin-default-cities '("Moscow")))
(use-package webpaste
:ensure t
:general
(:prefix "M-p"
"b" 'webpaste-paste-buffer
"r" 'webpaste-paste-region)
:custom
(webpaste-provider-priority '("ix.io" "gist.github.com")))
(use-package atomic-chrome
:ensure t
:custom
(atomic-chrome-buffer-open-style 'frame)
(atomic-chrome-server-ghost-text-port 4001)
:config
;; TODO: (alex3rd) make use of atomic-chrome-url-major-mode-alist
(atomic-chrome-start-server))
(use-package carbon-now-sh
:quelpa
(carbon-now-sh :repo "wiedzmin/carbon-now-sh.el" :fetcher github))
(use-package twittering-mode
:ensure t
:general
(:keymaps 'mode-specific-map
"5 t" 'twit)
:init
(setq twittering-use-master-password t)
(setq twittering-private-info-file (expand-file-name "~/docs/enc/cred/.twittering-mode.gpg")))
(use-package telega
:disabled
:quelpa
(telega :repo "zevlg/telega.el" :fetcher github :version original)
:custom
(telega-completing-read-function #'ivy-completing-read)
:hook (telega-root-mode . telega-notifications-mode)
:config
(use-package telega-notifications))
(use-package edit-server
:ensure t
:config
(edit-server-start))
update-desktop-database
URL:
javascript:location.href=’org-protocol://capture://l/’encodeURIComponent(location.href)’‘+encodeURIComponent(document.title)+’‘+encodeURIComponent(window.getSelection())
~/.local/share/applications/mimeapps.list [Default Applications] x-scheme-handler/org-protocol=org-protocol.desktop
~/.local/share/applications/org-protocol.desktop [Desktop Entry] Name=org-protocol Exec=emacsclient %u Type=Application Terminal=false Categories=System; MimeType=x-scheme-handler/org-protocol;
org-id usage example for the future: “* TODO___ %a\n :PROPERTIES:\n :ID: %(org-id-new)\n :END:\n %U\n\n %i”
(use-package org
:ensure org-plus-contrib
:after (f)
:mode (("\\.org$" . org-mode)
("\\.org_archive$" . org-mode))
:preface
(defun custom/finally-tangle-literate-config ()
(shell-command (format "ntangle %s" (concat user-emacs-directory literate-config-filename))))
;; remove read-only props from yanked text (e.g. from jabber.el chat buffer)
(defadvice org-yank (after make-yank-writeable disable)
(let ((inhibit-read-only t))
(remove-text-properties (region-beginning) (region-end)
'(read-only t))))
(defvar custom/org-journal-file (at-org-dir "/journal.org"))
(defvar custom/org-browser-tabs (at-org-dir "/browser-tabs.org"))
(defun custom/verify-refile-target () ;; Exclude DONE state tasks from refile targets
"Exclude todo keywords with a done state from refile targets"
(not (member (nth 2 (org-heading-components)) org-done-keywords)))
;;TODO: customize "todo-only" parameter for "org-tags-view"
(defun custom/follow-tag-link (tag)
"Display a list of TODO headlines with tag TAG.
With prefix argument, also display headlines without a TODO keyword."
(org-tags-view nil tag)) ;nil was (null current-prefix-arg) originally
;; http://irreal.org/blog/?p=6166
(defun custom/org-tags-all ()
;;TODO: bind some key to close buffer
(interactive)
(with-current-buffer (get-buffer-create "*org-tags*")
(delete-region (point-min) (point-max))
(org-mode)
;;TODO: review tag collection methods and find some truth
;; (sort (delete-dups (apply 'append (delete-dups (org-map-entries (lambda () org-scanner-tags) t 'agenda)))) 'string<)
(let ((tags (sort (delete-dups
(cl-loop for buffer in (org-buffer-list 'agenda t)
append (with-current-buffer buffer
(org-with-wide-buffer
(goto-char (point-min))
(cl-loop while (re-search-forward org-complex-heading-regexp nil t)
when (match-string 5)
append (split-string (substring-no-properties (match-string 5))
":" t "[[:space:]]+"))))))
'string<)))
(dolist (tag tags)
(insert (concat "[[elisp:(org-tags-view nil \"" tag "\")][" tag "]]\n"))))
(beginning-of-buffer)
(switch-to-buffer (current-buffer))
(read-only-mode)))
;; Remove empty CLOCK drawers on clock out
(defun custom/remove-empty-drawer-on-clock-out ()
(interactive)
(save-excursion
(beginning-of-line 0)
(org-remove-empty-drawer-at "CLOCK" (point))))
(defun custom/org-use-speed-commands-for-headings-and-lists ()
"Activate speed commands on list items too."
(or (and (looking-at org-outline-regexp) (looking-back "^\**"))
(save-excursion (and (looking-at (org-item-re)) (looking-back "^[ \t]*")))))
;; TODO: bind somewhere
(defun custom/org-capture-refile-and-jump ()
(interactive)
(org-capture-refile)
(org-refile-goto-last-stored))
;;TODO: investigate usage, seems useful
(defun custom/org-link-describe (link desc)
(cond ((string-match "file:" link)
(replace-regexp-in-string "^file:" "File link -> " (org-link-unescape link)))
(t (or desc link))))
;; (SEC-HIGH SEC-LOW MICROSEC PICOSEC) current-idle-time
(defvar custom/idle-clockout-timeout 1800
"Perform first attempt to clock-out after this period of emacs
inactivity. It can decide to postpone the clocking-out if it's
only emacs that is idle, but not the computer itself.")
(defvar custom/idle-clockout-recheck-interval 300
"After a sufficient idle time was achieved by emacs, we'll
periodically check current idle time of the whole OS to decide
whether we need to clock out")
(defvar custom/idle-clockout-repeat-timer nil
"Timer for repeatedly (during a single idle interval) checking
whether we need to clock-out")
(defun custom/clockout-when-idle ()
(awhen custom/idle-clockout-repeat-timer
(cancel-timer it))
(when (org-clocking-p)
(if (> (org-user-idle-seconds)
custom/idle-clockout-timeout)
(let ((org-clock-out-switch-to-state "WAITING")) ;TODO: introduce variable
(org-clock-out nil t))
(setf custom/idle-clockout-repeat-timer
(run-with-idle-timer
(time-add (current-idle-time) custom/idle-clockout-recheck-interval)
nil
'custom/clockout-when-idle)))))
:general
(:prefix "<f7>"
"g" 'org-clock-goto
"." 'org-clock-in
"," 'org-clock-out
"^" 'org-mru-clock-select-recent-task
"c" 'org-clock-cancel
"x" 'counsel-org-clock-context
"h" 'counsel-org-clock-history
"d" 'org-clock-display
"R" 'org-clock-report
"p" 'org-pomodoro
"s" 'org-schedule
"|" 'org-deadline
"t" 'org-toggle-timestamp-type
"e" 'org-capture
"w" 'org-store-link
"y" 'org-insert-link-global
"S" 'org-set-property
"D" 'org-delete-property
"A" 'org-footnote-action
"r" 'org-refile
"T" 'org-table-create
"a" 'org-agenda
"b" 'org-dashboard-display
"v" 'org-reveal
"f" 'ace-link-org
"n" 'org-narrow-to-subtree
"-" 'org-sparse-tree
"l" 'counsel-org-agenda-headlines
"H" 'org-recent-headings-ivy
"=" 'org-show-todo-tree
"\\" 'counsel-org-tag
"<right>" 'outline-next-visible-heading
"<left>" 'outline-previous-visible-heading
"<down>" 'org-forward-heading-same-level
"<up>" 'org-backward-heading-same-level
"u" 'outline-up-heading
"G" 'org-goto
";" 'custom/org-tags-all)
;; (:keymaps 'org-agenda-mode-map
;; "<f7> ." 'org-agenda-clock-in org-agenda-mode-map
;; "<f7> ," 'org-agenda-clock-out org-agenda-mode-map
;; "<f7> o" 'ace-link-org org-agenda-mode-map)
(:keymaps 'org-mode-map
"C-'" nil
"C-c [" nil
"C-c ]" nil
"C-c C-o" nil
"s-j" 'org-babel-next-src-block
"s-k" 'org-babel-previous-src-block
"s-l" 'org-edit-src-code
"C-c C-'" 'org-edit-src-code)
(:keymaps 'org-src-mode-map
"s-l" 'org-edit-src-exit
"C-c C-'" 'org-edit-src-exit)
:config
(use-package org-capture-pop-frame :ensure t)
(add-hook 'kill-emacs-hook #'custom/finally-tangle-literate-config)
(setq org-archive-location (concat custom/org-journal-file "::datetree/"))
(setq org-contrib-base '(org-agenda org-archive org-attach org-bbdb
org-bibtex org-clock org-docview org-habit
org-id org-info org-inlinetask org-irc
org-mouse org-protocol org-timer org-w3m))
(setq org-contrib-extra '(org-bookmark org-checklist org-collector
org-drill org-expiry org-index org-interactive-query
org-man org-velocity))
(setq org-modules `(,@org-contrib-base ,@org-contrib-extra))
(add-to-list 'file-coding-system-alist (cons "\\.\\(org\\|org_archive\\|/TODO\\)$" 'utf-8))
(setq org-lowest-priority 70) ;; extend priorities set (given ascii code)
(setq org-use-speed-commands 'custom/org-use-speed-commands-for-headings-and-lists)
(setq org-use-speed-commands t)
(add-to-list 'org-speed-commands-user '("x" org-todo "DONE"))
(add-to-list 'org-speed-commands-user '("y" org-todo-yesterday "DONE"))
(add-to-list 'org-speed-commands-user '("s" call-interactively 'org-schedule))
(add-to-list 'org-speed-commands-user '("i" call-interactively 'org-clock-in))
(add-to-list 'org-speed-commands-user '("o" call-interactively 'org-clock-out))
(add-to-list 'org-speed-commands-user '("$" call-interactively 'org-archive-subtree))
(f-entries (at-org-dir)
(lambda (entry) (when (and (f-file? entry)
(s-suffix? "org" entry)
(file-exists-p entry))
(push entry org-agenda-files)))
t)
(dolist (orgfile (directory-files (at-org-dir "/journals") t "journal") )
(setq org-agenda-files
(delete orgfile org-agenda-files)))
(add-to-list 'org-agenda-files (at-config-basedir "config.org"))
;; agenda customizations
(setq org-confirm-elisp-link-not-regexp "org-tags-view")
(setf org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2 :narrow 60))
(setq org-agenda-dim-blocked-tasks 'invisible)
(setq org-agenda-include-all-todo t)
(setq org-agenda-include-diary t)
(setq org-agenda-inhibit-startup t)
(setq org-agenda-persistent-filter t)
(setq org-agenda-repeating-timestamp-show-all nil)
(setq org-agenda-restore-windows-after-quit t)
(setq org-agenda-show-all-dates t)
(setq org-agenda-show-inherited-tags nil)
(setq org-agenda-show-log t)
(setq org-agenda-skip-additional-timestamps-same-entry t)
(setq org-agenda-skip-deadline-if-done t)
(setq org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled)
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-timestamp-if-done t)
(setq org-agenda-span 'month)
(setq org-agenda-start-on-weekday 1)
(setq org-agenda-sticky nil) ;otherwise agenda behaves strangely on non-stuck projects
(setq org-agenda-tags-todo-honor-ignore-options t)
(setq org-agenda-todo-ignore-deadlines 'all)
(setq org-agenda-todo-ignore-scheduled 'all)
(setq org-agenda-todo-ignore-timestamp 'past)
(setq org-agenda-todo-ignore-with-date t)
(setq org-agenda-todo-list-sublevels nil)
(setq org-agenda-use-tag-inheritance t)
(setq org-agenda-window-setup 'current-window)
(setf agenda-opts-all-with-time
'((org-agenda-todo-ignore-scheduled nil)
(org-agenda-todo-ignore-deadlines nil)
(org-agenda-todo-ignore-with-date nil)))
(setq org-agenda-time-grid
'((daily today require-timed remove-match)
"----------------"
(930 1000 1200 1400 1600 1800 2000 2200 2400 2500)))
(setq org-agenda-custom-commands
`(("d" . "some non-straightforward TODO statuses")
("db" todo "BACKLOG" nil)
("ds" todo "SOON" nil)
("dc" todo "CANCELLED" nil)
("dw" todo "WAITING|FEEDBACK" nil)
("dg" todo "GOING" ,agenda-opts-all-with-time)
("da" tags "+actual_p")
("c" . "by context")
("cp" tags "+@personal/GOING|WAITING|BACKLOG|SOON")
("cr" tags "+@project/GOING|WAITING|BACKLOG|SOON")
("cj" tags "+@job/GOING|WAITING|FEEDBACK|BACKLOG|SOON")
("cw" tags "+@workplace/GOING|WAITING|BACKLOG|SOON")
("ct" tags "+@phonecall/WAITING|BACKLOG|SOON")
("cs" tags "+@someday")
("cq" tags "+@quicknote")
("e" . "by essence")
;;TODO: find more handy shortcuts
("ec" tags "+current")
("ef" tags "+reference")
("em" tags "+master")
("eo" tags "+ordering")
("er" tags "+repair")
("ed" tags "+develop")
("ei" tags "+investigate")
("ee" tags "+entertainment")
("ey" tags "+family")
("eH" tags-todo "+housekeeping")
("eC" tags-todo "+current")
("eF" tags-todo "+reference")
("eM" tags-todo "+master")
("eO" tags-todo "+ordering")
("eR" tags-todo "+repair")
("eD" tags-todo "+develop")
("eI" tags-todo "+investigate")
("eE" tags-todo "+entertainment")
("u" . "unassigned")
("up" alltodo "Unprioritized TODO entries"
((org-agenda-skip-function
(lambda nil
(org-agenda-skip-entry-if 'regexp "\\[#[ABC]]")))
(org-tags-match-list-sublevels 'indented)
(org-agenda-sorting-strategy
'((agenda time-up tag-up) ))
;; '(org-agenda-sorting-strategy '((agenda time-up priority-down tag-up) (todo tag-up)))
(org-agenda-overriding-header "Unprioritized TODO entries: ")))
("P" . "Prioritized tasks")
("Pa" "Prioritized tasks A"
((tags-todo "+PRIORITY=\"A\"") ))
("Pb" "Prioritized tasks B"
((tags-todo "+PRIORITY=\"B\"")))
("Pc" "Prioritized tasks C"
((tags-todo "+PRIORITY=\"C\"")))
("S" "Scheduled tasks" agenda ""
((org-agenda-time-grid nil)
(org-deadline-warning-days 32)
(org-agenda-entry-types '(:scheduled))
))
("p" tags "+purchase")
("b" . "tickets")
("be" tags "+ticket+emacs")
("bs" tags "+ticket+stumpwm")
("jc" tags "+@job+current/GOING|FEEDBACK")
))
(setq org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t% s %b")
(timeline . " % s")
(todo . " %i %-12:c")
(tags . " %i %-12:c")
(search . " %i %-12:c")))
;; clocking customizations
(setq org-clock-history-length 35)
(setq org-clock-idle-time 3)
(setq org-clock-in-resume t)
(setq org-clock-in-switch-to-state "GOING")
(setq org-clock-out-switch-to-state "HOLD")
(setq org-clock-into-drawer "CLOCK")
(setq org-clock-out-remove-zero-time-clocks t)
(setq org-clock-persist t)
;; just clock-out unconditionally - it seems easier to maintain (credits to @binarin)
(setf org-clock-x11idle-program-name "xprintidle")
(setf org-x11idle-exists-p t)
;; refiling customizations
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-allow-creating-parent-nodes 'confirm)
(setq org-refile-target-verify-function 'custom/verify-refile-target)
(setq org-refile-targets '((org-agenda-files :maxlevel . 5) (nil :maxlevel . 5)))
(setq org-refile-use-outline-path 'file)
;; various customizations
(setf org-catch-invisible-edits nil)
(setf org-fast-tag-selection-include-todo nil)
(setf org-id-link-to-org-use-id t)
(setq appt-display-interval 5)
(setq appt-message-warning-time 10)
(setq calendar-date-style 'european)
(setq org-M-RET-may-split-line '((default . nil)))
(setq org-align-all-tags t)
(setq org-attach-directory (at-org-dir "/org-attach-data"))
(setq org-blank-before-new-entry '((heading) (plain-list-item . auto)))
(setq org-columns-default-format "%42ITEM %TODO %3Effort(E){:} %3CLOCKSUM_T(R) %SCHEDULED")
(setq org-confirm-elisp-link-function 'y-or-n-p)
(setq org-ctrl-k-protect-subtree t)
(setq org-cycle-include-plain-lists 'integrate)
(setq org-cycle-separator-lines 0)
(setq org-deadline-warning-days 30)
(setq org-default-notes-file (at-org-dir "/refile.org"))
(setq org-ditaa-jar-path (at-config-basedir "resources/ditaa0_9.jar"))
(setq org-element-use-cache nil)
(setq org-enforce-todo-checkbox-dependencies t)
(setq org-enforce-todo-dependencies t) ;;TODO: try ORDERED/NOBLOCKING props : org-toggle-ordered-property
(setq org-export-coding-system 'utf-8)
(setq org-export-with-drawers t)
(setq org-extend-today-until 2)
(setq org-fast-tag-selection-single-key 'expert)
(setq org-fontify-done-headline t)
(setq org-global-properties '(("STYLE_ALL" . "habit")))
(setq org-goto-max-level 10)
(setq org-hide-leading-stars t)
(setq org-indirect-buffer-display 'current-window)
(setq org-insert-mode-line-in-empty-file t)
(setq org-log-done t)
(setq org-log-into-drawer t)
(setq org-log-repeat 'time)
(setq org-loop-over-headlines-in-active-region t)
(setq org-read-date-prefer-future 'time)
(setq org-return-follows-link t)
(setq org-special-ctrl-a/e t)
(setq org-special-ctrl-k t)
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-startup-folded nil)
(setq org-stuck-projects '("+LEVEL=1/-DONE" ("TODO" "GOING" "NEXT" "WAITING" "HOLD" "CANCELLED") nil ""))
(setq org-tags-column -80)
(setq org-track-ordered-property-with-tag t)
(setq org-use-effective-time t)
(setq org-use-property-inheritance t)
(setq org-use-sub-superscripts nil)
(setq org-yank-adjusted-subtrees t)
(setq org-agenda-show-future-repeats 'next)
(setq org-highlight-latex-and-related '(latex))
(setq org-confirm-shell-link-function 'y-or-n-p)
(setq org-confirm-elisp-link-function 'y-or-n-p)
(setq org-src-window-setup 'current-window)
(setq org-confirm-babel-evaluate nil)
(setf org-make-link-description-function #'custom/org-link-describe)
(when (featurep 'unicode-fonts)
(setq org-ellipsis "⤵"))
;; keywords setup
(setq kw-seq-common '(sequence "BACKLOG(b)" "SOON(s)" "REPEAT(r)" "GOING(g!)" "NEXT(x)" "WAITING(w@/!)" "FEEDBACK"
"|" "DONE(d!/@)" "CANCELLED(c@/!)" "OUTDATED(o)"))
(setq org-todo-keywords
`(,kw-seq-common))
(setq org-todo-keywords-for-agenda '("BACKLOG(b)" "SOON(s)" "REPEAT(r)" "GOING(g!)" "NEXT(x)" "WAITING(w@/!)" "FEEDBACK"))
(setq org-done-keywords-for-agenda '("DONE(d)" "CANCELLED(c)" "OUTDATED(o)"))
;; faces
(setq org-todo-keyword-faces
'(("BACKLOG" . (:foreground "gray" :weight bold))
("SOON" . (:foreground "magenta" :weight bold))
("REPEAT" . (:foreground "blue" :weight bold))
("NEXT" . (:foreground "red" :weight bold))
("WAITING" . (:foreground "orange" :weight bold))
("FEEDBACK" . (:foreground "yellow" :weight bold))
("CANCELLED" . (:foreground "cyan" :weight bold))
("DONE" . (:foreground "green" :weight bold))))
(setq org-priority-faces
'((?A :foreground "red" :weight bold)
(?B :foreground "#94bff3" :weight bold)
(?C :foreground "#6f6f6f")
(?D :foreground "#c390d4")
(?E :foreground "#90c3d4")
(?F :foreground "#a1d490")))
(set-face-attribute 'org-done nil :foreground "PaleGreen" :weight 'normal :strike-through t)
(set-face-attribute 'org-headline-done nil :foreground "LightSalmon" :weight 'normal :strike-through t)
;; tags
(setq org-tag-alist '(("current" . ?c)
("reference" . ?f)
("orgmode" . ?g)
("purchase" . ?p)
("master" . ?m)
("ordering" . ?o)
("housekeeping" . ?h)
("entertainment" . ?e)
("interesting" . ?i)
("repair" . ?r)
))
(setq org-tags-exclude-from-inheritance '("project"))
(setq org-todo-state-tags-triggers
'(("GOING" ("current" . t))
("DONE" ("current"))))
;; org-habit
(setq org-habit-graph-column 50)
(setq org-habit-preceding-days 10)
(setq org-habit-following-days 4)
(setq org-habit-show-habits-only-for-today nil)
;; org-capture
(setq org-capture-templates
`(("n" "NixOS")
("nt" "NixOS" entry (file "/etc/nixos/todo.org") "* BACKLOG %?[[%:link][%:description]] %U\n %:initial")
("nc" "NixOS code snippet" entry (file "/etc/nixos/todo.org")
"* %^{title} :nix:code_snippet:\n :PROPERTIES:\n :CREATED: %U\n :END:\n\n#+BEGIN_SRC nix\n %i%?\n#+END_SRC\n")
("ns" "NixOS shell excerpt" entry (file "/etc/nixos/todo.org") "* %? %U :%:description:\n %:initial")
("e" "Emacs")
("et" "Emacs" entry (file ,(at-config-basedir "/todo.org")) "* BACKLOG %?[[%:link][%:description]] %U\n %:initial")
("ec" "Emacs code snippet" entry (file ,(at-config-basedir "/todo.org"))
"* %^{title} :emacs:code_snippet:\n :PROPERTIES:\n :CREATED: %U\n :END:\n\n#+BEGIN_SRC emacs-lisp\n %i%?\n#+END_SRC\n")
("es" "NixOS shell excerpt" entry (file ,(at-config-basedir "/todo.org")) "* %? %U :%:description:\n %:initial")
("x" "XMonad")
("xt" "XMonad" entry (file ,(at-homedir "/.xmonad/todo.org")) "* BACKLOG %?[[%:link][%:description]] %U\n %:initial")
("xc" "XMonad code snippet" entry (file ,(at-homedir "/.xmonad/todo.org"))
"* %^{title} :xmonad:code_snippet:\n :PROPERTIES:\n :CREATED: %U\n :END:\n\n#+BEGIN_SRC haskell\n %i%?\n#+END_SRC\n")
("xs" "XMonad shell excerpt" entry (file ,(at-homedir "/.xmonad/todo.org")) "* %? %U :%:description:\n %:initial")
("d" "deferred tabs" entry (file+olp custom/org-browser-tabs "groups" "deferred tabs") "* %?%:link %U :deferred:")
("p" "projects")
("pi" "project ideas" entry (file ,(at-org-dir "/projects.org")) "* %? %U :@project:idea:")
("pn" "new project" entry (file ,(at-org-dir "/projects.org")) "* %? %U :@project:")
("m" "mastering" entry (file+headline ,(at-org-dir "/mastering.org") "inbox") "* %? %U")
))
;; holidays
(setq holiday-orthodox-holidays nil) ; Orthodox holidays to some extent
(setq holiday-personal-holidays nil) ; personal anniversaries, etc.
(setq holiday-other-holidays
(append holiday-orthodox-holidays holiday-personal-holidays))
(setq calendar-holidays
(append holiday-other-holidays
holiday-solar-holidays))
(add-hook 'org-mode-hook 'turn-on-font-lock)
(add-hook 'org-clock-out-hook 'custom/remove-empty-drawer-on-clock-out 'append)
(add-hook 'org-after-refile-insert-hook 'save-buffer)
(add-hook 'org-capture-mode-hook
(lambda () (setq-local org-complete-tags-always-offer-all-agenda-tags t)))
;; run some commands
(org-add-link-type "tag" 'custom/follow-tag-link)
(org-clock-persistence-insinuate) ;; Resume clocking tasks when emacs is restarted
(run-at-time "06:00" 86400 '(lambda () (setq org-habit-show-habits t)))
(set-charset-priority 'unicode)
(turn-on-orgtbl)
(run-with-idle-timer custom/idle-clockout-timeout t 'custom/clockout-when-idle)
(font-lock-add-keywords
'org-mode
`(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 1 'org-headline-done prepend))
'append))
(use-package org-protocol
:after (org server))
(use-package ob-css
:ensure org-plus-contrib
:commands (org-babel-execute:css
org-babel-prep-session:css))
(use-package ob-dot
:ensure org-plus-contrib
:commands (org-babel-execute:dot
org-babel-expand-body:dot))
(use-package ob-ditaa
:ensure org-plus-contrib
:commands (org-babel-execute:ditaa
org-babel-prep-session:ditaa))
(use-package ob-emacs-lisp
:ensure org-plus-contrib
:commands (org-babel-execute:emacs-lisp
org-babel-expand-body:emacs-lisp))
(use-package ob-lisp
:ensure org-plus-contrib
:commands (org-babel-execute:lisp
org-babel-expand-body:lisp))
(use-package ob-js
:ensure org-plus-contrib
:commands (org-babel-execute:js
org-babel-prep-session:js
org-babel-variable-assignments:js))
(use-package ob-latex
:ensure org-plus-contrib
:commands (org-babel-execute:latex
org-babel-expand-body:latex
org-babel-prep-session:latex))
(use-package ob-org
:ensure org-plus-contrib
:commands (org-babel-execute:org
org-babel-expand-body:org
org-babel-prep-session:org))
(use-package ob-plantuml
:ensure org-plus-contrib
:commands (org-babel-execute:plantuml
org-babel-prep-session:plantuml
org-babel-variable-assignments:plantuml))
(use-package ob-scheme
:ensure org-plus-contrib
:commands (org-babel-execute:scheme
org-babel-expand-body:scheme))
(use-package ob-python
:ensure org-plus-contrib
:commands (org-babel-execute:python))
(use-package ob-shell
:ensure org-plus-contrib
:commands (org-babel-execute:sh
org-babel-expand-body:sh
org-babel-execute:bash
org-babel-expand-body:bash))
(use-package ox-html
:ensure org-plus-contrib
:commands (org-html-convert-region-to-html
org-html-export-as-html
org-html-export-to-html))
(use-package ob-async
:ensure t
:after (org ob))
(use-package org-pomodoro
:ensure t
:after (alert))
(use-package orgit
;;TODO: automate insertion of links below (yasnippet/whatever)
;; orgit:/path/to/repo/ links to a `magit-status' buffer
;; orgit-rev:/path/to/repo/::REV links to a `magit-revision' buffer
;; orgit-log:/path/to/repo/::ARGS links to a `magit-log' buffer
:ensure t)
(use-package orglink
:ensure t
:delight (orglink-mode " OL")
:config
;; TODO: customize orglink-activate-in-modes
;; TODO: automate insertion of link types below
;; [[Code]]
;; [[Code][start of code]]
;; [[define-derived-mode orglink-mode][orglink-mode]]
;; <mailto:[email protected]>
;; man:info
;; <info:man>
;; https://github.com/tarsius/orglink
(global-orglink-mode))
(use-package org-clock-today
:ensure t
:config
(org-clock-today-mode 1))
(use-package org-recent-headings
:ensure t
:disabled
:custom
(org-recent-headings-save-file (at-user-data-dir "org-recent-headings"))
:config
(org-recent-headings-mode 1))
(use-package org-link-minor-mode
:ensure t
:config
(org-link-minor-mode t))
(use-package org-randomnote
:ensure t
:general
(:keymaps 'mode-specific-map
"o r" 'org-randomnote)
:custom
(org-randomnote-candidates org-agenda-files)
(org-randomnote-open-behavior 'indirect-buffer))
(use-package russian-holidays
:ensure t
:after (org)
:config
(setq calendar-holidays
(push russian-holidays calendar-holidays)))
(use-package org-rich-yank
:ensure t
:after (org)
:general
(:keymaps 'org-mode-map
"C-M-y" 'org-rich-yank))
(use-package counsel-org-clock
:ensure t
:after (org counsel)
:custom
(counsel-org-clock-default-action 'counsel-org-clock-clock-dwim-action))
(use-package org-download
:ensure t
;;TODO: bind keys ASAP
;;TODO: use in automation
:hook (dired-mode-hook . org-download-enable)
:custom
(org-download-method 'attach))
(use-package blockdiag-mode :ensure t)
(use-package ob-blockdiag
:ensure t
:config
(org-babel-do-load-languages 'org-babel-load-languages
'((blockdiag . t))))
(use-package plantuml-mode
:ensure t
:mode ("\\.plantuml\\'" . plantuml-mode)
:custom
(plantuml-jar-path "/usr/share/plantuml/lib/plantuml.jar")
(org-plantuml-jar-path plantuml-jar-path)
:config
(add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
(org-babel-do-load-languages 'org-babel-load-languages
'((plantuml . t))))
(use-package info
:preface
(defun custom/open-info (topic bname)
"Open info on TOPIC in BNAME."
(if (get-buffer bname)
(progn
(switch-to-buffer bname)
(unless (string-match topic Info-current-file)
(Info-goto-node (format "(%s)" topic))))
(info topic bname)))
(defun custom/info-org () (custom/open-info "org" "*org info*"))
(defun custom/info-org-clocking () (org-info "Clocking commands"))
(defun custom/info-elisp () (custom/open-info "elisp" "*elisp info*"))
(defun custom/info-emacs () (custom/open-info "emacs" "*emacs info*"))
(defun custom/info-gcl () (custom/open-info "gcl" "*hyperspec*"))
:general
(:keymaps 'mode-specific-map
"C-h o" 'custom/open-org
"C-h ?" 'custom/info-org-clocking
"C-h e" 'custom/open-elisp
"C-h m" 'custom/open-emacs
"C-h h" 'custom/open-gcl)
:config
(info-initialize)
(setq Info-additional-directory-list
(list (concat home-directory "/help/info")))
(add-to-list 'Info-directory-list "/usr/share/info")
(add-to-list 'Info-directory-list
(format "%selpa/%s"
user-emacs-directory
(car (directory-files (at-config-basedir "elpa") nil "^use-package-")))))
(use-package helpful
:ensure t
:general
;;TODO: investigate more concise way
;;TODO: use C-u version (catch up TAPs)
(:prefix "<f1>"
"f" 'helpful-function
"v" 'helpful-variable
"C" 'helpful-callable
"m" 'helpful-macro
"c" 'helpful-command
"k" 'helpful-key
"RET" 'helpful-at-point)
(:prefix "C-h"
"f" 'helpful-function
"v" 'helpful-variable
"C" 'helpful-callable
"m" 'helpful-macro
"c" 'helpful-command
"k" 'helpful-key
"RET" 'helpful-at-point))
(use-package help-find-org-mode
:ensure t
:pin melpa-stable
:config (help-find-org-mode t))
(use-package info-buffer
:ensure t
:general
("C-h i" 'info-buffer))
(use-package info-colors
:ensure t
:hook (Info-selection-hook . info-colors-fontify-node))
(use-package woman
:config
(defalias 'man 'woman) ;'Woman' offers completion better than 'man'.
(setenv "MANPATH" "/usr/share/man:/usr/local/man"))
(use-package apropos
:general
(:keymaps 'mode-specific-map
"H a" 'apropos
"H d" 'apropos-documentation
"H v" 'apropos-variable
"H c" 'apropos-command
"H l" 'apropos-library
"H u" 'apropos-user-option
"H i" 'info-apropos
"H t" 'tags-apropos
"H e" 'apropos-value))