diff options
Diffstat (limited to 'user/emacs/init.el')
-rw-r--r-- | user/emacs/init.el | 999 |
1 files changed, 999 insertions, 0 deletions
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 + "<tab>" #'company-complete-common-or-cycle + "S-TAB" #'company-select-previous + "<backtab>" #'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 ("<M-tab>" #'company-tabnine-call-other-backends + "<C-tab>" #'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: |