(setq inhibit-startup-screen t initial-scratch-message "" initial-major-mode 'text-mode package-enable-at-startup nil) (eval-when-compile (require 'use-package) (setq use-package-expand-minimally t)) (setq use-package-always-demand (daemonp)) ;;; Customize (setq custom-file "~/.emacs.d/custom.el") (load custom-file :noerror :nomessage) (use-package crux) ;;; Styles (custom-set-variables ;; I prefer an always-visible cursor. Feels less distracting. '(blink-cursor-mode nil) ;; Disable all the bars, unless on OSX, in which case, keep the menu bar. '(menu-bar-mode nil) '(scroll-bar-mode nil) '(tool-bar-mode nil)) (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) (load-theme 'eink t) (setq frame-background-mode 'light) (mapc 'frame-set-background-mode (frame-list))) (global-hl-line-mode +1) ;;; Chrome (use-package minions :custom ((minions-mode-line-lighter "#") (minions-mode t))) (use-package moody :config (progn (setq x-underline-at-descent-line t) (moody-replace-mode-line-buffer-identification) (moody-replace-vc-mode))) (setq frame-title-format (list "Emacs")) (use-package ns-auto-titlebar :if (eq system-type 'darwin) :custom ((ns-auto-titlebar-mode t))) ;;; Dates & Times (custom-set-variables '(calendar-week-start-day 1) '(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 ;; I think =set-keyboard-coding-system= stops OS X from doing something ;; annoying to add accents. The modifier setup is to match my ;; re-arrangement of modifiers on OSX: Cmd on the outside, then ;; Option/alt, then Control. (when (eq system-type 'darwin) (custom-set-variables '(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 :custom ((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 :custom ((which-key-mode +1)) :config (progn (which-key-setup-side-window-right-bottom))) ;;; Modeline (use-package relative-buffers :custom ((global-relative-buffers-mode t))) ;;; Minibuffer (setq enable-recursive-minibuffers t) (minibuffer-depth-indicate-mode t) (use-package ivy :config (progn (ivy-mode +1))) (use-package ivy-hydra) (use-package swiper :general ([remap isearch-forward] #'swiper-isearch)) ;; transition smex history to amx (let ((smex-save-file (concat user-emacs-directory "smex-items"))) (use-package amx :custom ((amx-history-length 100)))) (use-package counsel :commands (counsel-unicode-char) :general ("M-x" #'counsel-M-x)) ;;; Windows (use-package eyebrowse :after (evil) :custom ((eyebrowse-new-workspace #'counsel-projectile-switch-project) (eyebrowse-mode t) (eyebrowse-mode-line-style 'always)) :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 :custom ((winner-mode t) (winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*"))) :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) :init (progn (defvar evil-want-integration) (defvar evil-want-keybinding) (setq evil-want-integration t evil-want-keybinding nil)) :custom ((evil-shift-width 2) (evil-mode-line-format '(before . mode-line-front-space))) :config (evil-mode +1) :general (:states 'motion "C-;" #'evil-avy-goto-line) (:states 'normal ";" #'evil-ex)) (use-package evil-collection :after (evil) :demand t :commands (evil-collection-init) :custom ((evil-collection-company-use-tng nil)) :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 :custom ((evil-space-mode t))) (use-package evil-surround :after evil :custom ((global-evil-surround-mode t))) (use-package evil-commentary :after evil :custom ((evil-commentary-mode t))) (use-package evil-magit :after (evil magit) :custom ((evil-magit-use-y-for-yank nil))) (use-package evil-quickscope :after evil :commands (evil-quickscope-mode) :ghook ('magit-mode-hook (lambda () (evil-quickscope-mode -1))) :custom ((global-evil-quickscope-mode t))) (use-package evil-org :after evil :commands (evil-org-set-key-theme) :ghook ('org-mode-hook #'evil-org-mode) :gfhook #'evil-org-set-key-theme) (use-package evil-org-agenda :after evil :ghook ('org-agenda-mode-hook #'evil-org-agenda-set-keys)) ;;; Projects (use-package projectile :defines projectile-command-map :custom ((projectile-mode +1) (projectile-completion-system 'ivy)) :config (progn (with-eval-after-load 'evil-ex (evil-ex-define-cmd "prg" #'projectile-ripgrep) ))) (use-package counsel-projectile :commands (counsel-projectile-switch-project counsel-projectile-rg counsel-projectile-switch-to-buffer) :after (counsel projectile ivy-hydra) :config (progn (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))) :custom ((counsel-projectile-mode +1))) (use-package magit :commands (magit-status magit-dispatch) :custom ((global-magit-file-mode +1) (magit-completing-read-function #'ivy-completing-read))) (eval-when-compile (require 'fringe-helper)) (use-package git-gutter) (use-package git-gutter-fringe :config (progn (global-git-gutter-mode 1) ;; 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 5 :custom ((git-messenger:use-magit-popup t))) (use-package git-timemachine) (use-package editorconfig :init (progn (unless (executable-find "editorconfig") (warn "Missing `editorconfig' executable."))) :config (editorconfig-mode +1)) ;;; Completion (use-package company :commands (company-explicit-action-p) :custom ((global-company-mode +1) (company-idle-delay .5) (company-begin-commands '(self-insert-command)) (company-auto-complete #'company-explicit-action-p) (company-auto-complete-chars '(?\ ?\( ?\) ?.))) :general (:states 'insert "TAB" #'company-complete)) (use-package all-the-icons) (use-package company-box :custom ((company-box-enable-icon nil) (company-dabbrev-downcase nil)) :ghook 'company-mode-hook) ;;; Documentation (use-package eldoc :custom ((global-eldoc-mode +1) (eldoc-idle-delay 0.5))) (use-package eldoc-box :after (eldoc eglot) :custom ((eldoc-box-hover-mode +1) (eldoc-box-hover-at-point-mode +1))) (use-package ehelp) (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 :custom ((global-auto-revert-mode t) (auto-revert-verbose 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)) (if (eq system-type 'darwin) (setq delete-by-moving-to-trash t) (if (and (executable-find "trash") (not (fboundp #'system-move-file-to-trash))) (defun system-move-file-to-trash (file) (call-process (executable-find "trash") nil 0 nil file)))) (use-package goto-chg :defer 1) ;;; Directories (custom-set-variables '(dired-dwim-target t) '(dired-recursive-copies 'top) '(dired-listing-switches "-alh") '(dired-recursive-deleted (if delete-by-moving-to-trash 'always 'top))) ;;; Shells (use-package eshell :defer 5 :functions (eshell/pwd) :custom ((eshell-prompt-function (lambda () (concat (eshell/pwd) "\n$ "))) (eshell-prompt-regexp "^[$][[:blank:]]"))) (use-package shell :general (:keymaps 'shell-mode-map "C-d" #'comint-delchar-or-maybe-eof)) (use-package comint :general (:keymaps 'comint-mode-map "C-c C-l" #'counsel-shell-history)) ;;; Editing (setq-default indent-tabs-mode nil) ;;; Major modes ;;;; js (custom-set-variables '(js-indent-level 2) '(js-enabled-frameworks '(javascript))) ;;;; typescript (custom-set-variables '(typescript-indent-level 2)) ;;;; 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)) (use-package sh-script :mode (("\\.zsh\\'" . shell-script-mode) ("zshenv\\'" . shell-script-mode) ("zshrc\\'" . shell-script-mode)) :config (setq sh-shell-file "/usr/bin/env zsh" sh-basic-offset 2)) (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) ;;;; nix (custom-set-variables '(nix-indent-function #'nix-indent-line)) ;;;; gitlab-ci.yml (with-eval-after-load 'git-gutter-fringe (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated) "XXX.....")) (custom-set-variables '(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 (custom-set-variables '(k8s-site-docs-version "v1.13")) ;;;; beancount (use-package beancount :load-path "~/projects/bitbucket.org/blais/beancount/editors/emacs") ;;;; org (custom-set-variables '(org-ellipsis "…") `(org-directory "~/Documents/org")) (use-package org-journal :commands (org-journal-new-date-entry org-journal-new-entry org-journal-new-scheduled-entry) :gfhook (#'variable-pitch-mode) :custom ((org-journal-date-format "%A, %d %B %Y") (org-journal-dir "~/Documents/journal"))) ;;;; emacs-lisp (use-package auto-async-byte-compile :ghook ('emacs-lisp-mode-hook #'enable-auto-async-byte-compile-mode)) ;;;; web modes (tsx, html) (use-package web-mode :mode (("\\.tsx" . web-mode)) :custom ((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 :custom ((flymake-error-bitmap '(left-vertical-bar compilation-error)) (flymake-warning-bitmap '(left-vertical-bar compilation-warning)))) (use-package lsp-mode :ghook ('typescript-mode-hook #'lsp) :custom ((lsp-auto-guess-root t) (lsp-prefer-flymake t) (lsp-enable-symbol-highlighting nil))) (use-package lsp-ui :after lsp-mode :ghook ('lsp-mode-hook) :custom ((lsp-ui-sideline-enable nil) (lsp-ui-doc-mode nil) (lsp-enable-snippet nil))) ;; 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 :ghook ('(js2-mode-hook typescript-mode-hook) #'add-node-modules-path)) ;;;; Reformat on save (use-package prettier-js :ghook ('(typescript-mode-hook js2-mode-hook) #'prettier-js-mode t)) ;;; Take me to my leader (my-leader-def "" nil "h" '(:keymap ehelp-map :package ehelp) "w" '(:keymap evil-window-map :package evil) "x" '(:keymap ctl-x-map) "q" #'evil-delete-buffer "p" projectile-command-map "v" #'split-window-right "o" #'other-window "u" #'universal-argument ";" #'counsel-M-x "bb" #'ivy-switch-buffer "bx" #'kill-this-buffer "br" #'revert-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) ;; # Local Variables: ;; # flycheck-disabled-checkers: 'emacs-lisp-checkdoc ;; # End: