From 7f527bb245c0dad5f827a24fe135611650ab082c Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 3 Apr 2020 13:27:46 +0200 Subject: Reorganise folder structure to remove hidden files After moving from GNU Stow, this is not necessary. Non-hidden files are much easier to work with. --- user/emacs/.emacs.d/init.el | 999 -------------------------------------------- user/emacs/init.el | 999 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 999 insertions(+), 999 deletions(-) delete mode 100644 user/emacs/.emacs.d/init.el create mode 100644 user/emacs/init.el (limited to 'user/emacs') diff --git a/user/emacs/.emacs.d/init.el b/user/emacs/.emacs.d/init.el deleted file mode 100644 index f76a5017..00000000 --- a/user/emacs/.emacs.d/init.el +++ /dev/null @@ -1,999 +0,0 @@ -;;; init --- user init file -*- lexical-binding: t; -*- -(setq inhibit-startup-echo-area-message "alan") -(setq inhibit-startup-screen t - initial-scratch-message "" - initial-major-mode 'fundamental-mode - package-enable-at-startup nil - evil-want-keybinding nil - frame-inhibit-implied-resize t) - -(let ((default-gc-cons-threshold (* 16 1024 1024)) - (default-file-name-handler-alist file-name-handler-alist)) - (setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6 - file-name-handler-alist nil) - (add-hook 'minibuffer-setup-hook (lambda () (setq gc-cons-threshold most-positive-fixnum))) - (add-hook 'minibuffer-exit-hook (lambda () (setq gc-cons-threshold default-gc-cons-threshold))) - (add-hook 'emacs-startup-hook (lambda () (setq file-name-handler-alist default-file-name-handler-alist))) - (add-hook 'after-init-hook (lambda () - (setq gc-cons-threshold default-gc-cons-threshold - gc-cons-percentage 0.1)))) - -(package-initialize) - -(defun reload-user-init-file () - "Reload init file." - (interactive) - (load-file user-init-file)) - -(eval-when-compile - (require 'use-package) - (setq use-package-expand-minimally t)) -(setq use-package-always-demand (daemonp)) - -(defvar ap/path-configured nil) -(when (and (eq system-type 'darwin) - (not ap/path-configured)) - (setq exec-path - (delete-dups - (append - (parse-colon-path - (elt (split-string-and-unquote - (with-output-to-string - (with-current-buffer standard-output - (call-process "/usr/libexec/path_helper" nil t nil "-s"))) - "[=;]") - 1)) - exec-path)) - ap/path-configured t)) - -;;; Customize - -(setq custom-file "~/.emacs.d/custom.el") -(load custom-file :noerror :nomessage) - -(use-package crux - :defer 1 - :config (crux-reopen-as-root-mode -1)) - -;;; Styles - - ;; I prefer an always-visible cursor. Feels less distracting. -(blink-cursor-mode -1) -;; Disable all the bars, unless on OSX, in which case, keep the menu bar. -(unless (eq system-type 'darwin) - (menu-bar-mode -1)) -(scroll-bar-mode -1) -(tool-bar-mode -1) -(set-fringe-mode '(4 . 4)) - -;; Ring the bell sometimes, but not so often -(setq ring-bell-function - (lambda () - (unless (memq this-command - '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit minibuffer-keyboard-quit undo-tree-undo)) - (ding)))) - -(when (or (daemonp) - window-system) - (use-package almost-mono-themes - :config (load-theme 'almost-mono-white t)) - (if (eq window-system 'x) - (setq-default line-spacing 0.2)) - (setq frame-background-mode 'light) - (mapc 'frame-set-background-mode (frame-list))) - -;;; Chrome -(column-number-mode +1) -(use-package doom-modeline - :hook (emacs-startup . doom-modeline-mode) - :config (progn - (setq doom-modeline-buffer-file-name-style 'relative-from-project - doom-modeline-buffer-icon nil - doom-modeline-buffer-modification-icon nil - doom-modeline-project-detection 'projectile - doom-modeline-vcs-max-length 24 - doom-modeline-env-version nil) - (let ((foreground (face-attribute 'font-lock-comment-face :foreground))) - (set-face-attribute 'doom-modeline-buffer-modified nil :foreground foreground)))) - -(when (eq system-type 'darwin) - (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) - (add-to-list 'default-frame-alist '(ns-appearance . 'light))) - -(add-to-list 'default-frame-alist '(width . 100)) -(add-to-list 'default-frame-alist '(height . 40)) - -;;; Dates & Times - -(defvar calendar-week-start-day 1) -(defvar calendar-date-style 'iso) - -(defun insert-date (prefix) - "Insert the current date. -With PREFIX, use British format. -With two prefix arguments, write out the day and month name." - (interactive "P") - (let ((format (cond - ((not prefix) "%Y-%m-%d") - ((equal prefix '(4)) "%d/%m/%Y") - ((equal prefix '(16)) "%A, %d %B %Y")))) - (insert (format-time-string format)))) - -(defun insert-datetime (prefix) - "Insert current date and time. With PREFIX, use ISO8601 format." - (interactive "P") - (let ((format (cond - ((not prefix) "%Y-%m-%d %H:%M:%S") - ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ")))) - (insert (format-time-string format)))) - -;;; Keybindings - -(when (eq system-type 'darwin) - (setq mac-option-modifier 'meta - mac-right-option-modifier 'none - mac-control-modifier 'control - mac-right-control-modifier 'left - mac-command-modifier 'super - mac-right-command-modifier 'left - mac-function-modifier 'hyper)) - -(use-package general - :functions (general-unbind general-define-key) - :config (progn - (general-override-mode +1) - (when (eq system-type 'darwin) - (general-unbind "s-x")))) - -(use-package avy - :defer 2 - :config (setq avy-all-windows nil)) -(use-package ace-link - :after avy - :commands (ace-link-setup-default) - :config (ace-link-setup-default)) - -;; Popup keybindings following a prefix automatically. - -(use-package which-key - :defer 5 - :config (progn - (which-key-mode +1) - (which-key-setup-side-window-right-bottom))) - -;;; Modeline - -(use-package relative-buffers - :defer 2 - :config (progn - (setq relative-buffers-project-prefix t) - (global-relative-buffers-mode +1))) - -;;; Minibuffer - -(setq enable-recursive-minibuffers t - save-silently t) -(minibuffer-depth-indicate-mode t) - -(use-package hydra - :defer 2) -(use-package ivy - :defer 1 - :config (progn - (ivy-mode +1))) -(use-package ivy-hydra - :defer 2) - -(use-package smerge-mode - :after magit - :config - (defhydra unpackaged/smerge-hydra - (:color pink :hint nil :post (smerge-auto-leave)) - " -^Move^ ^Keep^ ^Diff^ ^Other^ -^^-----------^^-------------------^^---------------------^^------- -_n_ext _b_ase _<_: upper/base _C_ombine -_p_rev _u_pper _=_: upper/lower _r_esolve -^^ _l_ower _>_: base/lower _k_ill current -^^ _a_ll _R_efine -^^ _RET_: current _E_diff -" - ("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) - ("w" (lambda () - (interactive) - (save-buffer) - (bury-buffer)) - "Save and bury buffer" :color blue) - ("q" nil "cancel" :color blue)) - :hook (magit-diff-visit-file . (lambda () - (when (bound-and-true-p smerge-mode) - (unpackaged/smerge-hydra/body))))) - -(use-package swiper - :general ([remap isearch-forward] #'swiper-isearch) - :config (progn - (setq ivy-count-format "%d/%d "))) - -(use-package amx - :config (setq amx-history-length 100)) - -(use-package counsel - :commands (counsel-unicode-char) - :general ("M-x" #'counsel-M-x)) - -;;; Windows - -(defun split-window-properly (&optional window) - (let ((window (or window (selected-window)))) - (or (and (window-splittable-p window) - ;; Split window vertically. - (with-selected-window window - (split-window-below))) - (and (window-splittable-p window t) - ;; Split window horizontally. - (with-selected-window window - (split-window-right)))))) - -(setq split-window-preferred-function #'split-window-properly - split-height-threshold nil - split-width-threshold 200) - -(use-package eyebrowse - :after (evil) - :config (progn - (setq eyebrowse-new-workspace t - eyebrowse-mode-line-left-delimiter "" - eyebrowse-mode-line-right-delimiter "" - eyebrowse-mode-line-separator " " - eyebrowse-mode-line-style 'always) - (eyebrowse-mode +1)) - :general (:keymaps 'evil-window-map - "0" #'eyebrowse-switch-to-window-config-0 - "1" #'eyebrowse-switch-to-window-config-1 - "2" #'eyebrowse-switch-to-window-config-2 - "3" #'eyebrowse-switch-to-window-config-3 - "4" #'eyebrowse-switch-to-window-config-4 - "5" #'eyebrowse-switch-to-window-config-5 - "6" #'eyebrowse-switch-to-window-config-6 - "7" #'eyebrowse-switch-to-window-config-7 - "8" #'eyebrowse-switch-to-window-config-8 - "9" #'eyebrowse-switch-to-window-config-9) - :ghook ('evil-after-load-hook #'eyebrowse-setup-evil-keys)) - -(use-package winner - :after evil - :defer 8 - :config (progn - (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")) - (winner-mode +1)) - :general (:keymaps 'evil-window-map - "u" #'winner-undo - "r" #'winner-redo - "C-r" #'winner-redo)) -;;; Evil - -(use-package evil - :demand t - :commands (evil-mode evil-delete-buffer evil-ex-define-cmd) - :config (progn - (setq-default evil-shift-width 2) - (setq evil-mode-line-format nil) - (add-to-list 'evil-emacs-state-modes 'eshell-mode) - (add-to-list 'evil-emacs-state-modes 'ledger-reconcile-mode) - (evil-mode +1)) - :general - (:states 'motion - "C-;" #'evil-avy-goto-line) - (:states 'normal - ";" #'evil-ex) - (:states '(normal motion) - "g s" #'evil-avy-goto-symbol-1)) - -(use-package evil-anzu - :defer 2 - :after evil) - -(defvar evil-collection-company-use-tng t) -(use-package evil-collection - :after (evil) - :defer 3 - :demand t - :commands (evil-collection-init) - :config (progn - (evil-collection-init))) - -(general-create-definer my-leader-def - :keymaps 'override - :states '(normal motion) - :prefix ",") - -(use-package evil-space - :defer 1 - :after evil - :config (evil-space-mode +1)) - -;; this macro was copied from here: https://stackoverflow.com/a/22418983/4921402 -(defmacro define-and-bind-quoted-text-object (name key start-regex end-regex) - (let ((inner-name (make-symbol (concat "evil-inner-" name))) - (outer-name (make-symbol (concat "evil-a-" name)))) - `(progn - (evil-define-text-object ,inner-name (count &optional beg end type) - (evil-select-paren ,start-regex ,end-regex beg end type count nil)) - (evil-define-text-object ,outer-name (count &optional beg end type) - (evil-select-paren ,start-regex ,end-regex beg end type count t)) - (define-key evil-inner-text-objects-map ,key #',inner-name) - (define-key evil-outer-text-objects-map ,key #',outer-name)))) - -(use-package evil-surround - :after evil - :defer 2 - :config (progn - (define-and-bind-quoted-text-object "slash" "/" "\\/" "\\/") - (push '(?\/ . ("/" . "/")) evil-surround-pairs-alist) - (global-evil-surround-mode +1))) - - -(use-package evil-embrace - :after evil-surround - :config (progn - (setq evil-embrace-show-help-p nil) - (push ?\/ evil-embrace-evil-surround-keys) - (evil-embrace-enable-evil-surround-integration) - (add-hook 'LaTeX-mode-hook #'embrace-LaTeX-mode-hook) - (add-hook 'org-mode-hook #'embrace-org-mode-hook) - (add-hook 'ruby-mode-hook #'embrace-ruby-mode-hook) - (add-hook 'emacs-lisp-mode-hook #'embrace-emacs-lisp-mode-hook))) - -(use-package evil-commentary - :after evil - :defer 2 - :config (evil-commentary-mode +1)) - -(use-package evil-magit - :after magit - :config (setq evil-magit-use-y-for-yank nil)) - -(use-package evil-matchit - :after evil - :defer 2 - :config (progn - (global-evil-matchit-mode +1))) - -(use-package evil-quickscope - :after evil - :commands (evil-quickscope-mode) - :ghook ('(magit-mode-hook git-rebase-mode-hook) #'turn-off-evil-quickscope-mode) - :config (global-evil-quickscope-mode +1)) - -(use-package evil-numbers - :after evil - :general (:states '(normal visual) - "C-a" #'evil-numbers/inc-at-pt - "C-q" #'evil-numbers/dec-at-pt)) - -(use-package evil-org - :after org - :commands (evil-org-set-key-theme) - :init (progn - (add-hook 'org-agenda-mode-hook #'evil-org-agenda-set-keys)) - :ghook ('org-mode-hook #'evil-org-mode) - :gfhook #'evil-org-set-key-theme) - - -;;; Projects - -(use-package projectile - :defer 1 - :defines projectile-command-map - :config (progn - (add-to-list 'projectile-globally-ignored-files "package-lock.json") - (add-to-list 'projectile-globally-ignored-files "pnpm-lock.yaml") - (add-to-list 'projectile-project-root-files "package.json") - (add-to-list 'projectile-project-root-files-bottom-up "pnpm-workspace.yaml") - (setq projectile-completion-system 'ivy - projectile-kill-buffers-filter 'kill-only-files - projectile-project-root-files-functions '(projectile-root-local - projectile-root-top-down - projectile-root-bottom-up - projectile-root-top-down-recurring)) - (projectile-mode +1) - (with-eval-after-load 'evil-ex - (evil-ex-define-cmd "rg" #'ripgrep-regexp) - (evil-ex-define-cmd "prg" #'projectile-ripgrep) - (evil-ex-define-cmd "pesh[ell]" #'projectile-run-eshell)))) - -(use-package counsel-projectile - :defer 1 - :commands (counsel-projectile-switch-project - counsel-projectile-rg - counsel-projectile-switch-to-buffer - counsel-projectile-mode) - :general (:keymaps 'projectile-command-map - "s s" #'counsel-projectile-rg - "s r" #'counsel-projectile-rg) - :config (progn - (assq-delete-all #'projectile-ripgrep counsel-projectile-key-bindings) - (counsel-projectile-mode +1) - (with-eval-after-load 'evil-ex - (evil-ex-define-cmd "cprg" #'counsel-projectile-rg) - (evil-ex-define-cmd "pb" #'counsel-projectile-switch-to-buffer) - (evil-ex-define-cmd "psw[itch]" #'counsel-projectile-switch-project)))) - -(use-package magit - :defer 10 - :commands (magit-status magit-dispatch) - :config (progn - (setq magit-auto-revert-mode nil magit-section-visibility-indicator nil - magit-diff-refine-hunk 'all - magit-display-buffer-function #'display-buffer - magit-completing-read-function #'ivy-completing-read) - (global-magit-file-mode +1) - (remove-hook 'magit-section-highlight-hook 'magit-section-highlight) - (remove-hook 'magit-section-highlight-hook 'magit-section-highlight-selection) - (remove-hook 'magit-section-highlight-hook 'magit-diff-highlight))) - -(eval-when-compile (require 'fringe-helper)) -(use-package git-gutter-fringe - :defer 5 - :config (progn - (global-git-gutter-mode 1) - (add-hook 'magit-post-refresh-hook - #'git-gutter:update-all-windows) - ;; places the git gutter outside the margins. - (setq-default fringes-outside-margins nil) - ;; thin fringe bitmaps - (fringe-helper-define 'git-gutter-fr:added '(center repeated) - ".XXX....") - (fringe-helper-define 'git-gutter-fr:modified '(center repeated) - ".XXX....") - (fringe-helper-define 'git-gutter-fr:deleted '(center repeated) - ".XXX....") - (setq git-gutter-fr:side 'right-fringe))) - -(use-package git-messenger - :commands (git-messenger:popup-message) - :defer 10 - :config (setq git-messenger:use-magit-popup t)) - -(use-package git-timemachine - :commands (git-timemachine)) - -(use-package editorconfig - :defer 2 - :init (progn - (unless (executable-find "editorconfig") - (warn "Missing `editorconfig' executable."))) - :config (editorconfig-mode +1)) - -;;; Completion - -(use-package company - :defer 2 - :commands (company-explicit-action-p) - :config (progn - (setq company-idle-delay 0.2 - company-tooltip-align-annotations t - company-show-numbers t - company-dabbrev-downcase nil - company-dabbrev-ignore-case nil - company-begin-commands '(self-insert-command) - company-auto-complete #'company-explicit-action-p - company-auto-complete-chars '(?\ ?\( ?\) ?.)) - (global-company-mode +1) - (general-unbind company-active-map - "RET" - [return])) - :general - (:states 'insert - "TAB" #'company-indent-or-complete-common) - (:keymaps 'company-active-map - "TAB" #'company-complete-common-or-cycle - "" #'company-complete-common-or-cycle - "S-TAB" #'company-select-previous - "" #'company-select-previous)) - -(use-package all-the-icons - :config (setq all-the-icons-color-icons nil)) - -(use-package company-tabnine - :commands (company-tabnine) - :after (company) - :config (setq company-tabnine-binaries-folder "~/.local/tabnine") - :general ("" #'company-tabnine-call-other-backends - "" #'company-tabnine-call-other-backends) - :init (progn - (add-to-list 'company-backends #'company-tabnine))) - -;;; Documentation - -(use-package eldoc - :defer 5 - :config (progn - (setq eldoc-idle-delay 0.5) - (global-eldoc-mode +1))) - -(use-package eldoc-box - :after (eldoc eglot) - :config (progn - (eldoc-box-hover-mode +1) - (eldoc-box-hover-at-point-mode +1))) - -(use-package ehelp - :defer 15) - -(use-package helpful - :after ehelp - :general (ehelp-map - "k" #'helpful-key - "v" #'helpful-variable - "f" #'helpful-callable)) - -;;; Files - -;;;; Auto-saving - -;; Auto-save everything to a temporary directory, instead of cluttering -;; the filesystem. I don’t want emacs-specific lockfiles, either. - -(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) - create-lockfiles nil) - -;;;; Auto-reloading - -(use-package autorevert - :defer 10 - :config (progn - (setq auto-revert-verbose t - auto-revert-use-notify t) - (global-auto-revert-mode t))) - -;;;; Backups - -;; I like to keep my backups out of regular folders. I tell emacs to use -;; a subfolder of its configuration directory for that. Also, use the -;; trash for deleting on OS X. -(let ((backup-dir (expand-file-name "~/.emacs.d/backups/"))) - (unless (file-directory-p backup-dir) - (make-directory backup-dir)) - (setq backup-directory-alist `((".*" . ,backup-dir)) - backup-by-copying-when-linked t - backup-by-copying-when-mismatch t)) - -(setq delete-by-moving-to-trash t) - -(use-package goto-chg - :defer 1) - -;;; Directories - -(setq dired-dwim-target t - dired-recursive-copies 'top - dired-listing-switches "-alh" - dired-recursive-deleted (if delete-by-moving-to-trash - 'always - 'top)) - -(add-hook 'dired-mode-hook - (lambda () - (dired-hide-details-mode))) - -(use-package dired-git-info - :general (:keymaps 'dired-mode-map - :states 'normal - ")" #'dired-git-info-mode)) - -;;; Shells - -(use-package eshell - :defer 5 - :commands (eshell) - :functions (eshell/pwd) - :init (progn - (with-eval-after-load 'evil-ex - (evil-ex-define-cmd "esh[ell]" #'eshell))) - :config (setq eshell-prompt-function (lambda () - (concat (eshell/pwd) "\n$ ")) - eshell-prompt-regexp "^[$][[:blank:]]" - eshell-cmpl-cycle-completions nil)) - -(use-package eshell-toggle - :after projectile - :commands (eshell-toggle) - :general ("C-`" #'eshell-toggle) - :config (setq eshell-toggle-use-projectile-root t)) - -(use-package esh-autosuggest - :after eshell - :ghook ('eshell-mode-hook)) - -(declare-function eshell-push-command "esh-buf-stack" (CMD)) -(defun my-bind-esh-push () - (general-define-key - :states '(normal insert) - :keymaps 'local - "M-q" #'eshell-push-command)) - -(use-package esh-buf-stack - :after (eshell) - :ghook ('eshell-mode-hook #'my-bind-esh-push) - :config (setup-eshell-buf-stack)) - -(use-package bash-completion - :after (eshell)) - -(use-package fish-completion - :when (executable-find "fish") - :after (bash-completion) - :commands (global-fish-completion-mode) - :config (progn - (setq fish-completion-fallback-on-bash-p t) - (global-fish-completion-mode))) - -(use-package esh-help - :after (eshell) - :config (setup-esh-help-eldoc)) - -(use-package eshell-fringe-status - :after eshell - :ghook '(eshell-mode-hook)) - -(use-package eshell-up - :after (eshell)) - -(use-package shell - :defer t - :general (:keymaps 'shell-mode-map - "C-d" #'comint-delchar-or-maybe-eof)) - -(use-package comint - :defer t - :general (:keymaps 'comint-mode-map - "C-c C-l" #'counsel-shell-history)) - -;;; Editing - -(setq-default indent-tabs-mode nil - tab-always-indent 'complete) - -(use-package ws-butler - :ghook ('prog-mode-hook)) - -;;; Major modes - -;;;; golang -(use-package go-mode - :defer t - :config (progn - (setq-default gofmt-command "goimports") - (add-hook 'go-mode-hook (lambda () - (add-hook 'before-save-hook #'gofmt-before-save) - (if (not (string-match-p "go" compile-command)) - (set (make-local-variable 'compile-command) - "go build -v && go test && go vet")))))) - -;;;; js -(setq js-indent-level 2 - js-enabled-frameworks '(javascript)) - -;;;; typescript -(setq typescript-indent-level 2) -(autoload 'ansi-color-apply-on-region "ansi-color") -(defun colorise-compilation-buffer () - (ansi-color-apply-on-region compilation-filter-start (point-max))) -(add-hook 'compilation-filter-hook #'colorise-compilation-buffer) - -;;;; shell -(general-add-hook 'sh-mode-hook - (lambda () - (general-add-hook 'after-save-hook - #'executable-make-buffer-file-executable-if-script-p :append :local))) - -(add-to-list 'auto-mode-alist '("\\.env\\'" . conf-unix-mode)) -(add-to-list 'auto-mode-alist '("\\.zsh\\'" . shell-script-mode)) -(add-to-list 'auto-mode-alist '("zshenv\\'" . shell-script-mode)) -(add-to-list 'auto-mode-alist '("zshrc\\'" . shell-script-mode)) -(setq sh-shell-file "/usr/bin/env zsh" - sh-basic-offset 2) - -(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) - -;;;; make -(general-add-hook 'makefile-mode-hook - (lambda () - (setq-local indent-tabs-mode t))) - -;;;; nix -(setq nix-indent-function #'nix-indent-line) - -(use-package nix-update - :commands (nix-update-fetch)) - -;;;; gitlab-ci.yml -(with-eval-after-load 'git-gutter-fringe - (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated) - "XXX.....")) - -(setq gitlab-ci-url "https://gitlab.satoshipay.tech") -(use-package gitlab-ci-mode-flycheck - :ghook ('gitlab-ci-mode-hook (list #'gitlab-ci-mode-flycheck-enable - #'flycheck-mode))) - -;;;; *ignore -(use-package gitignore-mode - :mode ((".dockerignore\\'" . gitignore-mode))) - -;;;; kubernetes -(setq k8s-site-docs-version "v1.13") - -(use-package kubel - :defer t) - -(use-package kubel-evil - :ghook 'kubel-mode-hook) - -;;;; ledger - -(use-package ledger-mode - :gfhook '(ledger-flymake-enable ws-butler-mode) - :defer t - :config (progn - (setq ledger-reconcile-default-commodity "€" - ledger-narrow-on-reconcile t - ledger-clear-whole-transactions t - ledger-reports `(("Monthly Expenses" "ledger -f %(ledger-file) reg -M \\^Expenses --real -X EUR -l \"payee != 'Opening Balances'\"") - ("Total Expenses:This Month" "ledger -f %(ledger-file) bal \\^Expenses -p \"this month\"") - ("Total Expenses:Past 90 Days" ,(concat "ledger -f %(ledger-file) balance ^Expenses -b " - (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -90))))) - ("Total Expenses:Past 180 Days" ,(concat "ledger -f %(ledger-file) balance ^Expenses -b " - (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -180))))) - ("Expenses:This Month" "ledger -f %(ledger-file) register \\^Expenses -p \"this month\"") - ("Expenses:Past 90 Days (monthly)" ,(concat "ledger -f %(ledger-file) register --monthly ^Expenses -b " - (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -90))))) - ("Expenses:Past 180 Days (monthly)" ,(concat "ledger -f %(ledger-file) register --monthly ^Expenses -b " - (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -180))))) - ("All Account Balances" "ledger -f %(ledger-file) bal --current -R \\^Assets \\^Liabilities"))))) - - -(use-package evil-ledger - :after ledger-mode - :ghook '(ledger-mode-hook)) - -;;;; org - -(setq org-ellipsis "…" - org-directory "~/Documents/org") - -(use-package org-journal - :after org - :commands (org-journal-new-date-entry - org-journal-new-entry - org-journal-new-scheduled-entry) - :gfhook (#'variable-pitch-mode) - :config (setq org-journal-date-format "%A, %d %B %Y" - org-journal-dir "~/Documents/journal")) - -;;;; web modes (tsx, html) - -(use-package css-mode - :defer t - :config (progn - (setq css-indent-offset 2))) - -(use-package web-mode - :mode (("\\.tsx\\'" . web-mode) - ("\\.html?\\'" . web-mode)) - :config (setq web-mode-enable-auto-pairing nil - web-mode-code-indent-offset 2 - web-mode-markup-indent-offset 2 - web-mode-css-indent-offset 2 - web-mode-style-padding 0 - web-mode-script-padding 0)) - -;;; IDE features - -(fringe-helper-define 'left-vertical-bar '(center repeated) - "XXX.....") -(use-package flymake - :defer 5 - :config (setq flymake-error-bitmap '(left-vertical-bar compilation-error) - flymake-warning-bitmap '(left-vertical-bar compilation-warning))) -(use-package flycheck - :defer 5 - :ghook ('(typescript-mode-hook - dockerfile-mode-hook - yaml-mode-hook - js-mode-hook - css-mode-hook - scss-mode-hook - html-mode-hook - haskell-mode-hook)) - :config (progn - (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled) - flycheck-highlighting-mode 'sexps) - (flycheck-define-error-level 'error - :severity 100 - :compilation-level 2 - :overlay-category 'flycheck-error-overlay - :fringe-bitmap 'left-vertical-bar - :fringe-face 'flycheck-fringe-error - :error-list-face 'flycheck-error-list-error) - (flycheck-define-error-level 'warning - :severity 10 - :compilation-level 1 - :overlay-category 'flycheck-warning-overlay - :fringe-bitmap 'left-vertical-bar - :fringe-face 'flycheck-fringe-warning - :warning-list-face 'flycheck-error-list-warning) - (flycheck-define-error-level 'info - :severity -10 - :compilation-level 0 - :overlay-category 'flycheck-info-overlay - :fringe-bitmap 'left-vertical-bar - :fringe-face 'flycheck-fringe-info - :info-list-face 'flycheck-error-list-info))) - - -(use-package treemacs - :defer t - :config (progn - (setq treemacs-no-png-images t))) - -(use-package lsp-mode - :defer 2 - :general (:states 'normal :keymaps 'lsp-mode-map - "gd" #'xref-find-definitions - "gr" #'xref-find-references - "C-t" #'xref-pop-marker-stack) - :ghook ('(typescript-mode-hook - dockerfile-mode-hook - yaml-mode-hook - js-mode-hook - css-mode-hook - go-mode-hook - scss-mode-hook - html-mode-hook - haskell-mode-hook) - #'lsp-deferred) - :config (progn - (require 'lsp-clients) - (setq lsp-auto-guess-root t - lsp-auto-configure nil - lsp-idle-delay 0.5 - lsp-enable-symbol-highlighting nil) - (add-to-list 'lsp-language-id-configuration '(js-mode . "javascript")))) - -(use-package lsp-ui - :after lsp-mode - :ghook ('lsp-mode-hook) - :general (:states 'normal :keymaps 'lsp-ui-mode-map - "gd" #'lsp-ui-peek-find-definitions - "gr" #'lsp-ui-peek-find-references - "C-t" #'lsp-ui-peek-jump-backward) - :config (progn - (setq lsp-enable-snippet nil - lsp-ui-sideline-show-code-actions nil - lsp-ui-sideline-enable t - lsp-ui-doc-enable nil))) - -(use-package lsp-haskell - :after lsp-mode) - -;; Inside a javascript project, it's common to install tools locally to -;; the project. This will allows emacs to find their executables. - -(use-package add-node-modules-path - :config (setq add-node-modules-max-depth 6) - :ghook ('(js2-mode-hook typescript-mode-hook) #'add-node-modules-path)) - -;;;; Reformat on save - -(use-package prettier-js - :ghook ('(javascript-mode-hook typescript-mode-hook) #'prettier-js-mode t) - :config (progn - (setq prettier-js-show-errors 'echo) - (if-let ((prettier_d (executable-find "prettier_d"))) - (setq prettier-js-command prettier_d - prettier-js-args '("--pkg-conf" "--parser" "typescript")) - (message "prettier_d is not available")))) - -;;; E-mail - -(declare-function sendmail-send-it "sendmail") -(setq send-mail-function #'sendmail-send-it) - -(use-package mu4e - :if (executable-find "mu") - :commands (mu4e) - :defines (mu4e-contexts) - :init (progn - (with-eval-after-load 'evil-ex - (evil-ex-define-cmd "mu[4e]" #'mu4e))) - :config (progn - (setq mail-user-agent #'mu4e-user-agent - mu4e-completing-read-function #'ivy-completing-read - mu4e-maildir "~/mail" - mu4e-context-policy 'pick-first - mu4e-update-interval 600 - mu4e-change-filenames-when-moving t - mu4e-index-lazy-check t - mu4e-hide-index-messages t - mu4e-compose-format-flowed t - mu4e-contexts (list - (make-mu4e-context - :name "SatoshiPay" - :match-func (lambda (msg) - (if msg - (mu4e-message-contact-field-matches - msg :to ".*@satoshipay.io") - (string-equal (system-name) "satoshipad"))) - :vars '((user-mail-address . "alan@satoshipay.io") - (mu4e-sent-messages-behavior . delete) - (mu4e-drafts-folder . "/satoshipay/[Gmail]/Drafts") - (mu4e-sent-folder . "/satoshipay/[Gmail]/Sent Mail") - (mu4e-refile-folder . "/satoshipay/[Gmail]/All Mail") - (mu4e-trash-folder . "/satoshipay/[Gmail]/Bin") - (mu4e-maildir-shortcuts . (("/satoshipay/INBOX" . ?i) - ("/satoshipay/[Gmail]/All Mail" . ?a) - ("/satoshipay/[Gmail]/Sent Mail" . ?s) - ("/satoshipay/[Gmail]/Spam" . ?p) - ("/satoshipay/[Gmail]/Spam" . ?j))))))))) - -;;; Take me to my leader - -(my-leader-def - "" nil - "`" #'eshell-toggle - "h" '(:keymap ehelp-map :package ehelp) - "w" '(:keymap evil-window-map :package evil) - "x" '(:keymap ctl-x-map) - "c" (general-simulate-key "C-c") - "q" #'evil-delete-buffer - "p" '(:keymap projectile-command-map :package projectile) - "v" #'split-window-right - "o" #'other-window - "u" #'universal-argument - ";" #'counsel-M-x - "bb" #'counsel-switch-buffer - "bx" #'kill-this-buffer - "br" #'revert-buffer - "bk" #'kill-buffer - "dd" #'dired - "fs" #'save-buffer - "ff" #'find-file - "fw" #'write-file - "fd" #'crux-delete-file-and-buffer - "fr" #'crux-rename-file-and-buffer - "gs" #'magit-status - "gm" #'git-messenger:popup-message - "gg" #'magit-dispatch - "gn" #'git-gutter:next-hunk - "gp" #'git-gutter:previous-hunk - "gi" #'git-gutter:popup-hunk - "gs" #'git-gutter:stage-hunk - "go" #'git-gutter:revert-hunk - "gt" #'git-timemachine - "bi" #'ibuffer - "bz" #'bury-buffer - "iu" #'counsel-unicode-char) - -(load (expand-file-name "mail.el" user-emacs-directory) :noerror) - -;; # Local Variables: -;; # flycheck-disabled-checkers: 'emacs-lisp-checkdoc -;; # End: diff --git a/user/emacs/init.el b/user/emacs/init.el new file mode 100644 index 00000000..f76a5017 --- /dev/null +++ b/user/emacs/init.el @@ -0,0 +1,999 @@ +;;; init --- user init file -*- lexical-binding: t; -*- +(setq inhibit-startup-echo-area-message "alan") +(setq inhibit-startup-screen t + initial-scratch-message "" + initial-major-mode 'fundamental-mode + package-enable-at-startup nil + evil-want-keybinding nil + frame-inhibit-implied-resize t) + +(let ((default-gc-cons-threshold (* 16 1024 1024)) + (default-file-name-handler-alist file-name-handler-alist)) + (setq gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.6 + file-name-handler-alist nil) + (add-hook 'minibuffer-setup-hook (lambda () (setq gc-cons-threshold most-positive-fixnum))) + (add-hook 'minibuffer-exit-hook (lambda () (setq gc-cons-threshold default-gc-cons-threshold))) + (add-hook 'emacs-startup-hook (lambda () (setq file-name-handler-alist default-file-name-handler-alist))) + (add-hook 'after-init-hook (lambda () + (setq gc-cons-threshold default-gc-cons-threshold + gc-cons-percentage 0.1)))) + +(package-initialize) + +(defun reload-user-init-file () + "Reload init file." + (interactive) + (load-file user-init-file)) + +(eval-when-compile + (require 'use-package) + (setq use-package-expand-minimally t)) +(setq use-package-always-demand (daemonp)) + +(defvar ap/path-configured nil) +(when (and (eq system-type 'darwin) + (not ap/path-configured)) + (setq exec-path + (delete-dups + (append + (parse-colon-path + (elt (split-string-and-unquote + (with-output-to-string + (with-current-buffer standard-output + (call-process "/usr/libexec/path_helper" nil t nil "-s"))) + "[=;]") + 1)) + exec-path)) + ap/path-configured t)) + +;;; Customize + +(setq custom-file "~/.emacs.d/custom.el") +(load custom-file :noerror :nomessage) + +(use-package crux + :defer 1 + :config (crux-reopen-as-root-mode -1)) + +;;; Styles + + ;; I prefer an always-visible cursor. Feels less distracting. +(blink-cursor-mode -1) +;; Disable all the bars, unless on OSX, in which case, keep the menu bar. +(unless (eq system-type 'darwin) + (menu-bar-mode -1)) +(scroll-bar-mode -1) +(tool-bar-mode -1) +(set-fringe-mode '(4 . 4)) + +;; Ring the bell sometimes, but not so often +(setq ring-bell-function + (lambda () + (unless (memq this-command + '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit minibuffer-keyboard-quit undo-tree-undo)) + (ding)))) + +(when (or (daemonp) + window-system) + (use-package almost-mono-themes + :config (load-theme 'almost-mono-white t)) + (if (eq window-system 'x) + (setq-default line-spacing 0.2)) + (setq frame-background-mode 'light) + (mapc 'frame-set-background-mode (frame-list))) + +;;; Chrome +(column-number-mode +1) +(use-package doom-modeline + :hook (emacs-startup . doom-modeline-mode) + :config (progn + (setq doom-modeline-buffer-file-name-style 'relative-from-project + doom-modeline-buffer-icon nil + doom-modeline-buffer-modification-icon nil + doom-modeline-project-detection 'projectile + doom-modeline-vcs-max-length 24 + doom-modeline-env-version nil) + (let ((foreground (face-attribute 'font-lock-comment-face :foreground))) + (set-face-attribute 'doom-modeline-buffer-modified nil :foreground foreground)))) + +(when (eq system-type 'darwin) + (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) + (add-to-list 'default-frame-alist '(ns-appearance . 'light))) + +(add-to-list 'default-frame-alist '(width . 100)) +(add-to-list 'default-frame-alist '(height . 40)) + +;;; Dates & Times + +(defvar calendar-week-start-day 1) +(defvar calendar-date-style 'iso) + +(defun insert-date (prefix) + "Insert the current date. +With PREFIX, use British format. +With two prefix arguments, write out the day and month name." + (interactive "P") + (let ((format (cond + ((not prefix) "%Y-%m-%d") + ((equal prefix '(4)) "%d/%m/%Y") + ((equal prefix '(16)) "%A, %d %B %Y")))) + (insert (format-time-string format)))) + +(defun insert-datetime (prefix) + "Insert current date and time. With PREFIX, use ISO8601 format." + (interactive "P") + (let ((format (cond + ((not prefix) "%Y-%m-%d %H:%M:%S") + ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ")))) + (insert (format-time-string format)))) + +;;; Keybindings + +(when (eq system-type 'darwin) + (setq mac-option-modifier 'meta + mac-right-option-modifier 'none + mac-control-modifier 'control + mac-right-control-modifier 'left + mac-command-modifier 'super + mac-right-command-modifier 'left + mac-function-modifier 'hyper)) + +(use-package general + :functions (general-unbind general-define-key) + :config (progn + (general-override-mode +1) + (when (eq system-type 'darwin) + (general-unbind "s-x")))) + +(use-package avy + :defer 2 + :config (setq avy-all-windows nil)) +(use-package ace-link + :after avy + :commands (ace-link-setup-default) + :config (ace-link-setup-default)) + +;; Popup keybindings following a prefix automatically. + +(use-package which-key + :defer 5 + :config (progn + (which-key-mode +1) + (which-key-setup-side-window-right-bottom))) + +;;; Modeline + +(use-package relative-buffers + :defer 2 + :config (progn + (setq relative-buffers-project-prefix t) + (global-relative-buffers-mode +1))) + +;;; Minibuffer + +(setq enable-recursive-minibuffers t + save-silently t) +(minibuffer-depth-indicate-mode t) + +(use-package hydra + :defer 2) +(use-package ivy + :defer 1 + :config (progn + (ivy-mode +1))) +(use-package ivy-hydra + :defer 2) + +(use-package smerge-mode + :after magit + :config + (defhydra unpackaged/smerge-hydra + (:color pink :hint nil :post (smerge-auto-leave)) + " +^Move^ ^Keep^ ^Diff^ ^Other^ +^^-----------^^-------------------^^---------------------^^------- +_n_ext _b_ase _<_: upper/base _C_ombine +_p_rev _u_pper _=_: upper/lower _r_esolve +^^ _l_ower _>_: base/lower _k_ill current +^^ _a_ll _R_efine +^^ _RET_: current _E_diff +" + ("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) + ("w" (lambda () + (interactive) + (save-buffer) + (bury-buffer)) + "Save and bury buffer" :color blue) + ("q" nil "cancel" :color blue)) + :hook (magit-diff-visit-file . (lambda () + (when (bound-and-true-p smerge-mode) + (unpackaged/smerge-hydra/body))))) + +(use-package swiper + :general ([remap isearch-forward] #'swiper-isearch) + :config (progn + (setq ivy-count-format "%d/%d "))) + +(use-package amx + :config (setq amx-history-length 100)) + +(use-package counsel + :commands (counsel-unicode-char) + :general ("M-x" #'counsel-M-x)) + +;;; Windows + +(defun split-window-properly (&optional window) + (let ((window (or window (selected-window)))) + (or (and (window-splittable-p window) + ;; Split window vertically. + (with-selected-window window + (split-window-below))) + (and (window-splittable-p window t) + ;; Split window horizontally. + (with-selected-window window + (split-window-right)))))) + +(setq split-window-preferred-function #'split-window-properly + split-height-threshold nil + split-width-threshold 200) + +(use-package eyebrowse + :after (evil) + :config (progn + (setq eyebrowse-new-workspace t + eyebrowse-mode-line-left-delimiter "" + eyebrowse-mode-line-right-delimiter "" + eyebrowse-mode-line-separator " " + eyebrowse-mode-line-style 'always) + (eyebrowse-mode +1)) + :general (:keymaps 'evil-window-map + "0" #'eyebrowse-switch-to-window-config-0 + "1" #'eyebrowse-switch-to-window-config-1 + "2" #'eyebrowse-switch-to-window-config-2 + "3" #'eyebrowse-switch-to-window-config-3 + "4" #'eyebrowse-switch-to-window-config-4 + "5" #'eyebrowse-switch-to-window-config-5 + "6" #'eyebrowse-switch-to-window-config-6 + "7" #'eyebrowse-switch-to-window-config-7 + "8" #'eyebrowse-switch-to-window-config-8 + "9" #'eyebrowse-switch-to-window-config-9) + :ghook ('evil-after-load-hook #'eyebrowse-setup-evil-keys)) + +(use-package winner + :after evil + :defer 8 + :config (progn + (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")) + (winner-mode +1)) + :general (:keymaps 'evil-window-map + "u" #'winner-undo + "r" #'winner-redo + "C-r" #'winner-redo)) +;;; Evil + +(use-package evil + :demand t + :commands (evil-mode evil-delete-buffer evil-ex-define-cmd) + :config (progn + (setq-default evil-shift-width 2) + (setq evil-mode-line-format nil) + (add-to-list 'evil-emacs-state-modes 'eshell-mode) + (add-to-list 'evil-emacs-state-modes 'ledger-reconcile-mode) + (evil-mode +1)) + :general + (:states 'motion + "C-;" #'evil-avy-goto-line) + (:states 'normal + ";" #'evil-ex) + (:states '(normal motion) + "g s" #'evil-avy-goto-symbol-1)) + +(use-package evil-anzu + :defer 2 + :after evil) + +(defvar evil-collection-company-use-tng t) +(use-package evil-collection + :after (evil) + :defer 3 + :demand t + :commands (evil-collection-init) + :config (progn + (evil-collection-init))) + +(general-create-definer my-leader-def + :keymaps 'override + :states '(normal motion) + :prefix ",") + +(use-package evil-space + :defer 1 + :after evil + :config (evil-space-mode +1)) + +;; this macro was copied from here: https://stackoverflow.com/a/22418983/4921402 +(defmacro define-and-bind-quoted-text-object (name key start-regex end-regex) + (let ((inner-name (make-symbol (concat "evil-inner-" name))) + (outer-name (make-symbol (concat "evil-a-" name)))) + `(progn + (evil-define-text-object ,inner-name (count &optional beg end type) + (evil-select-paren ,start-regex ,end-regex beg end type count nil)) + (evil-define-text-object ,outer-name (count &optional beg end type) + (evil-select-paren ,start-regex ,end-regex beg end type count t)) + (define-key evil-inner-text-objects-map ,key #',inner-name) + (define-key evil-outer-text-objects-map ,key #',outer-name)))) + +(use-package evil-surround + :after evil + :defer 2 + :config (progn + (define-and-bind-quoted-text-object "slash" "/" "\\/" "\\/") + (push '(?\/ . ("/" . "/")) evil-surround-pairs-alist) + (global-evil-surround-mode +1))) + + +(use-package evil-embrace + :after evil-surround + :config (progn + (setq evil-embrace-show-help-p nil) + (push ?\/ evil-embrace-evil-surround-keys) + (evil-embrace-enable-evil-surround-integration) + (add-hook 'LaTeX-mode-hook #'embrace-LaTeX-mode-hook) + (add-hook 'org-mode-hook #'embrace-org-mode-hook) + (add-hook 'ruby-mode-hook #'embrace-ruby-mode-hook) + (add-hook 'emacs-lisp-mode-hook #'embrace-emacs-lisp-mode-hook))) + +(use-package evil-commentary + :after evil + :defer 2 + :config (evil-commentary-mode +1)) + +(use-package evil-magit + :after magit + :config (setq evil-magit-use-y-for-yank nil)) + +(use-package evil-matchit + :after evil + :defer 2 + :config (progn + (global-evil-matchit-mode +1))) + +(use-package evil-quickscope + :after evil + :commands (evil-quickscope-mode) + :ghook ('(magit-mode-hook git-rebase-mode-hook) #'turn-off-evil-quickscope-mode) + :config (global-evil-quickscope-mode +1)) + +(use-package evil-numbers + :after evil + :general (:states '(normal visual) + "C-a" #'evil-numbers/inc-at-pt + "C-q" #'evil-numbers/dec-at-pt)) + +(use-package evil-org + :after org + :commands (evil-org-set-key-theme) + :init (progn + (add-hook 'org-agenda-mode-hook #'evil-org-agenda-set-keys)) + :ghook ('org-mode-hook #'evil-org-mode) + :gfhook #'evil-org-set-key-theme) + + +;;; Projects + +(use-package projectile + :defer 1 + :defines projectile-command-map + :config (progn + (add-to-list 'projectile-globally-ignored-files "package-lock.json") + (add-to-list 'projectile-globally-ignored-files "pnpm-lock.yaml") + (add-to-list 'projectile-project-root-files "package.json") + (add-to-list 'projectile-project-root-files-bottom-up "pnpm-workspace.yaml") + (setq projectile-completion-system 'ivy + projectile-kill-buffers-filter 'kill-only-files + projectile-project-root-files-functions '(projectile-root-local + projectile-root-top-down + projectile-root-bottom-up + projectile-root-top-down-recurring)) + (projectile-mode +1) + (with-eval-after-load 'evil-ex + (evil-ex-define-cmd "rg" #'ripgrep-regexp) + (evil-ex-define-cmd "prg" #'projectile-ripgrep) + (evil-ex-define-cmd "pesh[ell]" #'projectile-run-eshell)))) + +(use-package counsel-projectile + :defer 1 + :commands (counsel-projectile-switch-project + counsel-projectile-rg + counsel-projectile-switch-to-buffer + counsel-projectile-mode) + :general (:keymaps 'projectile-command-map + "s s" #'counsel-projectile-rg + "s r" #'counsel-projectile-rg) + :config (progn + (assq-delete-all #'projectile-ripgrep counsel-projectile-key-bindings) + (counsel-projectile-mode +1) + (with-eval-after-load 'evil-ex + (evil-ex-define-cmd "cprg" #'counsel-projectile-rg) + (evil-ex-define-cmd "pb" #'counsel-projectile-switch-to-buffer) + (evil-ex-define-cmd "psw[itch]" #'counsel-projectile-switch-project)))) + +(use-package magit + :defer 10 + :commands (magit-status magit-dispatch) + :config (progn + (setq magit-auto-revert-mode nil magit-section-visibility-indicator nil + magit-diff-refine-hunk 'all + magit-display-buffer-function #'display-buffer + magit-completing-read-function #'ivy-completing-read) + (global-magit-file-mode +1) + (remove-hook 'magit-section-highlight-hook 'magit-section-highlight) + (remove-hook 'magit-section-highlight-hook 'magit-section-highlight-selection) + (remove-hook 'magit-section-highlight-hook 'magit-diff-highlight))) + +(eval-when-compile (require 'fringe-helper)) +(use-package git-gutter-fringe + :defer 5 + :config (progn + (global-git-gutter-mode 1) + (add-hook 'magit-post-refresh-hook + #'git-gutter:update-all-windows) + ;; places the git gutter outside the margins. + (setq-default fringes-outside-margins nil) + ;; thin fringe bitmaps + (fringe-helper-define 'git-gutter-fr:added '(center repeated) + ".XXX....") + (fringe-helper-define 'git-gutter-fr:modified '(center repeated) + ".XXX....") + (fringe-helper-define 'git-gutter-fr:deleted '(center repeated) + ".XXX....") + (setq git-gutter-fr:side 'right-fringe))) + +(use-package git-messenger + :commands (git-messenger:popup-message) + :defer 10 + :config (setq git-messenger:use-magit-popup t)) + +(use-package git-timemachine + :commands (git-timemachine)) + +(use-package editorconfig + :defer 2 + :init (progn + (unless (executable-find "editorconfig") + (warn "Missing `editorconfig' executable."))) + :config (editorconfig-mode +1)) + +;;; Completion + +(use-package company + :defer 2 + :commands (company-explicit-action-p) + :config (progn + (setq company-idle-delay 0.2 + company-tooltip-align-annotations t + company-show-numbers t + company-dabbrev-downcase nil + company-dabbrev-ignore-case nil + company-begin-commands '(self-insert-command) + company-auto-complete #'company-explicit-action-p + company-auto-complete-chars '(?\ ?\( ?\) ?.)) + (global-company-mode +1) + (general-unbind company-active-map + "RET" + [return])) + :general + (:states 'insert + "TAB" #'company-indent-or-complete-common) + (:keymaps 'company-active-map + "TAB" #'company-complete-common-or-cycle + "" #'company-complete-common-or-cycle + "S-TAB" #'company-select-previous + "" #'company-select-previous)) + +(use-package all-the-icons + :config (setq all-the-icons-color-icons nil)) + +(use-package company-tabnine + :commands (company-tabnine) + :after (company) + :config (setq company-tabnine-binaries-folder "~/.local/tabnine") + :general ("" #'company-tabnine-call-other-backends + "" #'company-tabnine-call-other-backends) + :init (progn + (add-to-list 'company-backends #'company-tabnine))) + +;;; Documentation + +(use-package eldoc + :defer 5 + :config (progn + (setq eldoc-idle-delay 0.5) + (global-eldoc-mode +1))) + +(use-package eldoc-box + :after (eldoc eglot) + :config (progn + (eldoc-box-hover-mode +1) + (eldoc-box-hover-at-point-mode +1))) + +(use-package ehelp + :defer 15) + +(use-package helpful + :after ehelp + :general (ehelp-map + "k" #'helpful-key + "v" #'helpful-variable + "f" #'helpful-callable)) + +;;; Files + +;;;; Auto-saving + +;; Auto-save everything to a temporary directory, instead of cluttering +;; the filesystem. I don’t want emacs-specific lockfiles, either. + +(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) + create-lockfiles nil) + +;;;; Auto-reloading + +(use-package autorevert + :defer 10 + :config (progn + (setq auto-revert-verbose t + auto-revert-use-notify t) + (global-auto-revert-mode t))) + +;;;; Backups + +;; I like to keep my backups out of regular folders. I tell emacs to use +;; a subfolder of its configuration directory for that. Also, use the +;; trash for deleting on OS X. +(let ((backup-dir (expand-file-name "~/.emacs.d/backups/"))) + (unless (file-directory-p backup-dir) + (make-directory backup-dir)) + (setq backup-directory-alist `((".*" . ,backup-dir)) + backup-by-copying-when-linked t + backup-by-copying-when-mismatch t)) + +(setq delete-by-moving-to-trash t) + +(use-package goto-chg + :defer 1) + +;;; Directories + +(setq dired-dwim-target t + dired-recursive-copies 'top + dired-listing-switches "-alh" + dired-recursive-deleted (if delete-by-moving-to-trash + 'always + 'top)) + +(add-hook 'dired-mode-hook + (lambda () + (dired-hide-details-mode))) + +(use-package dired-git-info + :general (:keymaps 'dired-mode-map + :states 'normal + ")" #'dired-git-info-mode)) + +;;; Shells + +(use-package eshell + :defer 5 + :commands (eshell) + :functions (eshell/pwd) + :init (progn + (with-eval-after-load 'evil-ex + (evil-ex-define-cmd "esh[ell]" #'eshell))) + :config (setq eshell-prompt-function (lambda () + (concat (eshell/pwd) "\n$ ")) + eshell-prompt-regexp "^[$][[:blank:]]" + eshell-cmpl-cycle-completions nil)) + +(use-package eshell-toggle + :after projectile + :commands (eshell-toggle) + :general ("C-`" #'eshell-toggle) + :config (setq eshell-toggle-use-projectile-root t)) + +(use-package esh-autosuggest + :after eshell + :ghook ('eshell-mode-hook)) + +(declare-function eshell-push-command "esh-buf-stack" (CMD)) +(defun my-bind-esh-push () + (general-define-key + :states '(normal insert) + :keymaps 'local + "M-q" #'eshell-push-command)) + +(use-package esh-buf-stack + :after (eshell) + :ghook ('eshell-mode-hook #'my-bind-esh-push) + :config (setup-eshell-buf-stack)) + +(use-package bash-completion + :after (eshell)) + +(use-package fish-completion + :when (executable-find "fish") + :after (bash-completion) + :commands (global-fish-completion-mode) + :config (progn + (setq fish-completion-fallback-on-bash-p t) + (global-fish-completion-mode))) + +(use-package esh-help + :after (eshell) + :config (setup-esh-help-eldoc)) + +(use-package eshell-fringe-status + :after eshell + :ghook '(eshell-mode-hook)) + +(use-package eshell-up + :after (eshell)) + +(use-package shell + :defer t + :general (:keymaps 'shell-mode-map + "C-d" #'comint-delchar-or-maybe-eof)) + +(use-package comint + :defer t + :general (:keymaps 'comint-mode-map + "C-c C-l" #'counsel-shell-history)) + +;;; Editing + +(setq-default indent-tabs-mode nil + tab-always-indent 'complete) + +(use-package ws-butler + :ghook ('prog-mode-hook)) + +;;; Major modes + +;;;; golang +(use-package go-mode + :defer t + :config (progn + (setq-default gofmt-command "goimports") + (add-hook 'go-mode-hook (lambda () + (add-hook 'before-save-hook #'gofmt-before-save) + (if (not (string-match-p "go" compile-command)) + (set (make-local-variable 'compile-command) + "go build -v && go test && go vet")))))) + +;;;; js +(setq js-indent-level 2 + js-enabled-frameworks '(javascript)) + +;;;; typescript +(setq typescript-indent-level 2) +(autoload 'ansi-color-apply-on-region "ansi-color") +(defun colorise-compilation-buffer () + (ansi-color-apply-on-region compilation-filter-start (point-max))) +(add-hook 'compilation-filter-hook #'colorise-compilation-buffer) + +;;;; shell +(general-add-hook 'sh-mode-hook + (lambda () + (general-add-hook 'after-save-hook + #'executable-make-buffer-file-executable-if-script-p :append :local))) + +(add-to-list 'auto-mode-alist '("\\.env\\'" . conf-unix-mode)) +(add-to-list 'auto-mode-alist '("\\.zsh\\'" . shell-script-mode)) +(add-to-list 'auto-mode-alist '("zshenv\\'" . shell-script-mode)) +(add-to-list 'auto-mode-alist '("zshrc\\'" . shell-script-mode)) +(setq sh-shell-file "/usr/bin/env zsh" + sh-basic-offset 2) + +(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) + +;;;; make +(general-add-hook 'makefile-mode-hook + (lambda () + (setq-local indent-tabs-mode t))) + +;;;; nix +(setq nix-indent-function #'nix-indent-line) + +(use-package nix-update + :commands (nix-update-fetch)) + +;;;; gitlab-ci.yml +(with-eval-after-load 'git-gutter-fringe + (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated) + "XXX.....")) + +(setq gitlab-ci-url "https://gitlab.satoshipay.tech") +(use-package gitlab-ci-mode-flycheck + :ghook ('gitlab-ci-mode-hook (list #'gitlab-ci-mode-flycheck-enable + #'flycheck-mode))) + +;;;; *ignore +(use-package gitignore-mode + :mode ((".dockerignore\\'" . gitignore-mode))) + +;;;; kubernetes +(setq k8s-site-docs-version "v1.13") + +(use-package kubel + :defer t) + +(use-package kubel-evil + :ghook 'kubel-mode-hook) + +;;;; ledger + +(use-package ledger-mode + :gfhook '(ledger-flymake-enable ws-butler-mode) + :defer t + :config (progn + (setq ledger-reconcile-default-commodity "€" + ledger-narrow-on-reconcile t + ledger-clear-whole-transactions t + ledger-reports `(("Monthly Expenses" "ledger -f %(ledger-file) reg -M \\^Expenses --real -X EUR -l \"payee != 'Opening Balances'\"") + ("Total Expenses:This Month" "ledger -f %(ledger-file) bal \\^Expenses -p \"this month\"") + ("Total Expenses:Past 90 Days" ,(concat "ledger -f %(ledger-file) balance ^Expenses -b " + (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -90))))) + ("Total Expenses:Past 180 Days" ,(concat "ledger -f %(ledger-file) balance ^Expenses -b " + (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -180))))) + ("Expenses:This Month" "ledger -f %(ledger-file) register \\^Expenses -p \"this month\"") + ("Expenses:Past 90 Days (monthly)" ,(concat "ledger -f %(ledger-file) register --monthly ^Expenses -b " + (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -90))))) + ("Expenses:Past 180 Days (monthly)" ,(concat "ledger -f %(ledger-file) register --monthly ^Expenses -b " + (format-time-string "%Y-%m-%d" (time-add (current-time) (days-to-time -180))))) + ("All Account Balances" "ledger -f %(ledger-file) bal --current -R \\^Assets \\^Liabilities"))))) + + +(use-package evil-ledger + :after ledger-mode + :ghook '(ledger-mode-hook)) + +;;;; org + +(setq org-ellipsis "…" + org-directory "~/Documents/org") + +(use-package org-journal + :after org + :commands (org-journal-new-date-entry + org-journal-new-entry + org-journal-new-scheduled-entry) + :gfhook (#'variable-pitch-mode) + :config (setq org-journal-date-format "%A, %d %B %Y" + org-journal-dir "~/Documents/journal")) + +;;;; web modes (tsx, html) + +(use-package css-mode + :defer t + :config (progn + (setq css-indent-offset 2))) + +(use-package web-mode + :mode (("\\.tsx\\'" . web-mode) + ("\\.html?\\'" . web-mode)) + :config (setq web-mode-enable-auto-pairing nil + web-mode-code-indent-offset 2 + web-mode-markup-indent-offset 2 + web-mode-css-indent-offset 2 + web-mode-style-padding 0 + web-mode-script-padding 0)) + +;;; IDE features + +(fringe-helper-define 'left-vertical-bar '(center repeated) + "XXX.....") +(use-package flymake + :defer 5 + :config (setq flymake-error-bitmap '(left-vertical-bar compilation-error) + flymake-warning-bitmap '(left-vertical-bar compilation-warning))) +(use-package flycheck + :defer 5 + :ghook ('(typescript-mode-hook + dockerfile-mode-hook + yaml-mode-hook + js-mode-hook + css-mode-hook + scss-mode-hook + html-mode-hook + haskell-mode-hook)) + :config (progn + (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled) + flycheck-highlighting-mode 'sexps) + (flycheck-define-error-level 'error + :severity 100 + :compilation-level 2 + :overlay-category 'flycheck-error-overlay + :fringe-bitmap 'left-vertical-bar + :fringe-face 'flycheck-fringe-error + :error-list-face 'flycheck-error-list-error) + (flycheck-define-error-level 'warning + :severity 10 + :compilation-level 1 + :overlay-category 'flycheck-warning-overlay + :fringe-bitmap 'left-vertical-bar + :fringe-face 'flycheck-fringe-warning + :warning-list-face 'flycheck-error-list-warning) + (flycheck-define-error-level 'info + :severity -10 + :compilation-level 0 + :overlay-category 'flycheck-info-overlay + :fringe-bitmap 'left-vertical-bar + :fringe-face 'flycheck-fringe-info + :info-list-face 'flycheck-error-list-info))) + + +(use-package treemacs + :defer t + :config (progn + (setq treemacs-no-png-images t))) + +(use-package lsp-mode + :defer 2 + :general (:states 'normal :keymaps 'lsp-mode-map + "gd" #'xref-find-definitions + "gr" #'xref-find-references + "C-t" #'xref-pop-marker-stack) + :ghook ('(typescript-mode-hook + dockerfile-mode-hook + yaml-mode-hook + js-mode-hook + css-mode-hook + go-mode-hook + scss-mode-hook + html-mode-hook + haskell-mode-hook) + #'lsp-deferred) + :config (progn + (require 'lsp-clients) + (setq lsp-auto-guess-root t + lsp-auto-configure nil + lsp-idle-delay 0.5 + lsp-enable-symbol-highlighting nil) + (add-to-list 'lsp-language-id-configuration '(js-mode . "javascript")))) + +(use-package lsp-ui + :after lsp-mode + :ghook ('lsp-mode-hook) + :general (:states 'normal :keymaps 'lsp-ui-mode-map + "gd" #'lsp-ui-peek-find-definitions + "gr" #'lsp-ui-peek-find-references + "C-t" #'lsp-ui-peek-jump-backward) + :config (progn + (setq lsp-enable-snippet nil + lsp-ui-sideline-show-code-actions nil + lsp-ui-sideline-enable t + lsp-ui-doc-enable nil))) + +(use-package lsp-haskell + :after lsp-mode) + +;; Inside a javascript project, it's common to install tools locally to +;; the project. This will allows emacs to find their executables. + +(use-package add-node-modules-path + :config (setq add-node-modules-max-depth 6) + :ghook ('(js2-mode-hook typescript-mode-hook) #'add-node-modules-path)) + +;;;; Reformat on save + +(use-package prettier-js + :ghook ('(javascript-mode-hook typescript-mode-hook) #'prettier-js-mode t) + :config (progn + (setq prettier-js-show-errors 'echo) + (if-let ((prettier_d (executable-find "prettier_d"))) + (setq prettier-js-command prettier_d + prettier-js-args '("--pkg-conf" "--parser" "typescript")) + (message "prettier_d is not available")))) + +;;; E-mail + +(declare-function sendmail-send-it "sendmail") +(setq send-mail-function #'sendmail-send-it) + +(use-package mu4e + :if (executable-find "mu") + :commands (mu4e) + :defines (mu4e-contexts) + :init (progn + (with-eval-after-load 'evil-ex + (evil-ex-define-cmd "mu[4e]" #'mu4e))) + :config (progn + (setq mail-user-agent #'mu4e-user-agent + mu4e-completing-read-function #'ivy-completing-read + mu4e-maildir "~/mail" + mu4e-context-policy 'pick-first + mu4e-update-interval 600 + mu4e-change-filenames-when-moving t + mu4e-index-lazy-check t + mu4e-hide-index-messages t + mu4e-compose-format-flowed t + mu4e-contexts (list + (make-mu4e-context + :name "SatoshiPay" + :match-func (lambda (msg) + (if msg + (mu4e-message-contact-field-matches + msg :to ".*@satoshipay.io") + (string-equal (system-name) "satoshipad"))) + :vars '((user-mail-address . "alan@satoshipay.io") + (mu4e-sent-messages-behavior . delete) + (mu4e-drafts-folder . "/satoshipay/[Gmail]/Drafts") + (mu4e-sent-folder . "/satoshipay/[Gmail]/Sent Mail") + (mu4e-refile-folder . "/satoshipay/[Gmail]/All Mail") + (mu4e-trash-folder . "/satoshipay/[Gmail]/Bin") + (mu4e-maildir-shortcuts . (("/satoshipay/INBOX" . ?i) + ("/satoshipay/[Gmail]/All Mail" . ?a) + ("/satoshipay/[Gmail]/Sent Mail" . ?s) + ("/satoshipay/[Gmail]/Spam" . ?p) + ("/satoshipay/[Gmail]/Spam" . ?j))))))))) + +;;; Take me to my leader + +(my-leader-def + "" nil + "`" #'eshell-toggle + "h" '(:keymap ehelp-map :package ehelp) + "w" '(:keymap evil-window-map :package evil) + "x" '(:keymap ctl-x-map) + "c" (general-simulate-key "C-c") + "q" #'evil-delete-buffer + "p" '(:keymap projectile-command-map :package projectile) + "v" #'split-window-right + "o" #'other-window + "u" #'universal-argument + ";" #'counsel-M-x + "bb" #'counsel-switch-buffer + "bx" #'kill-this-buffer + "br" #'revert-buffer + "bk" #'kill-buffer + "dd" #'dired + "fs" #'save-buffer + "ff" #'find-file + "fw" #'write-file + "fd" #'crux-delete-file-and-buffer + "fr" #'crux-rename-file-and-buffer + "gs" #'magit-status + "gm" #'git-messenger:popup-message + "gg" #'magit-dispatch + "gn" #'git-gutter:next-hunk + "gp" #'git-gutter:previous-hunk + "gi" #'git-gutter:popup-hunk + "gs" #'git-gutter:stage-hunk + "go" #'git-gutter:revert-hunk + "gt" #'git-timemachine + "bi" #'ibuffer + "bz" #'bury-buffer + "iu" #'counsel-unicode-char) + +(load (expand-file-name "mail.el" user-emacs-directory) :noerror) + +;; # Local Variables: +;; # flycheck-disabled-checkers: 'emacs-lisp-checkdoc +;; # End: -- cgit 1.4.1