Compare commits

..

15 Commits

Author SHA1 Message Date
Jeremy Dormitzer
6df2f155ec Add commands to do dired stuff in directory at point 2021-02-20 22:03:56 -05:00
Jeremy Dormitzer
76f2f9ff9a Fix esup init file location 2021-02-20 22:03:44 -05:00
Jeremy Dormitzer
1df2d62921 Add highlight-indent-guides-mode 2021-02-20 22:03:33 -05:00
Jeremy Dormitzer
224556e35e Fix aggressive-indent-mode hooks 2021-02-20 22:02:45 -05:00
Jeremy Dormitzer
4578eba781 Bind consult-yank 2021-02-20 22:02:33 -05:00
Jeremy Dormitzer
8ccb8bf9c5 Add AWS utilities 2021-02-20 22:02:19 -05:00
Jeremy Dormitzer
9cd8d7d414 Add run-command 2021-02-20 22:01:52 -05:00
Jeremy Dormitzer
c3fc728d98 Add Clojure, Python, Terraform, and YAML config 2021-02-20 22:01:34 -05:00
Jeremy Dormitzer
68e30e2455 Add shell command keybindings 2021-02-20 22:01:15 -05:00
Jeremy Dormitzer
e041bd724b Defer loading of built-ins 2021-02-20 22:01:03 -05:00
Jeremy Dormitzer
6aeb373f54 Remove unnecessary call to (epa-file-enable) 2021-02-20 22:00:37 -05:00
Jeremy Dormitzer
70e8ba5d52 Add elisp utility lib 2021-02-20 22:00:23 -05:00
Jeremy Dormitzer
92b74eda73 Formatting 2021-02-20 22:00:11 -05:00
Jeremy Dormitzer
37ecaec0d8 Add startup optimizations 2021-02-20 21:59:29 -05:00
Jeremy Dormitzer
8dde9d65dc Set lexical binding everywhere 2021-02-20 21:59:11 -05:00
29 changed files with 492 additions and 9 deletions

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Get a nice interface to pass
(use-package pass
:commands pass
@ -13,8 +15,6 @@
(normal pass-mode-map "S" #'password-store-synchronize))
(use-package password-store
:init
(epa-file-enable)
:general
(leader-map "Pg" #'password-store-copy)
:custom

View File

@ -0,0 +1,44 @@
;; -*- lexical-binding: t; -*-
;; Manage AWS profiles
(defvar aws-profiles '("default")
"AWS profile names")
(defvar aws-current-profile nil
"Currently active AWS profile")
(defun aws-local-profile ()
(make-local-variable 'aws-current-profile))
(add-hook 'eshell-mode-hook #'aws-local-profile)
(add-hook 'vterm-mode-hook #'aws-local-profile)
(add-hook 'term-mode-hook #'aws-local-profile)
(setq aws-current-profile (getenv "AWS_PROFILE"))
(add-to-list 'aws-profiles "personal")
(add-to-list 'aws-profiles "lola-cde")
(defun aws-switch-profile (profile)
(interactive (list (completing-read "Profile: " aws-profiles)))
(setenv "AWS_PROFILE" profile)
(setq aws-current-profile profile))
;; A command to MFA to AWS
(defun aws-mfa (mfa-token)
(interactive (list
(let ((prompt (if aws-current-profile
(format "MFA code for %s: " aws-current-profile)
"MFA code: ")))
(read-from-minibuffer prompt))))
(let ((proc (start-process "aws-mfa"
"*aws-mfa*"
"aws-mfa"
"--force")))
(set-process-sentinel
proc
(make-success-err-msg-sentinel "*aws-mfa*"
"AWS MFA succeeded"
"AWS MFA failed, check *aws-mfa* buffer for details"))
(process-send-string proc (concat mfa-token "\n"))))
(provide 'init-aws)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Buffer-related configuration
(defun kill-other-buffers ()
"Kill all other buffers."

View File

@ -1,17 +1,24 @@
;; -*- lexical-binding: t; -*-
;; Configuration for built-ins that don't fit anywhere else
(use-package custom
:straight (:type built-in)
:defer t
:config
(evil-collection-custom-setup))
(use-package view
:straight (:type built-in)
:defer t
:config
(evil-collection-view-setup))
(use-package simple
:straight (:type built-in)
:general
(leader-map "!" #'shell-command
"|" #'shell-command-on-region
";" #'async-shell-command)
(normal special-mode-map
"gr" #'revert-buffer
"q" #'quit-window)
@ -19,4 +26,9 @@
"gr" #'revert-buffer
"q" #'quit-window))
(use-package shell
:straight (:type built-in)
:general
(normal shell-mode-map "q" #'bury-buffer))
(provide 'init-built-ins)

View File

@ -0,0 +1,50 @@
;; -*- lexical-binding: t; -*-
;; Clojure configuration
(use-package clojure-mode
:mode (("\\.clj\\'" . clojure-mode)
("\\.cljs\\'" . clojurescript-mode)
("\\.cljc\\'" . clojurec-mode)
("\\.edn\\'" . clojure-mode))
:config
(define-clojure-indent
(defroutes 'defun)
(GET 2)
(POST 2)
(PUT 2)
(DELETE 2)
(HEAD 2)
(ANY 2)
(OPTIONS 2)
(PATCH 2)
(rfn 2)
(let-routes 1)
(context 2)
(:= 3)
(:+ 3)
(match 1)
(for-all 2)
(checking 2)
(let-flow 1)))
;; Flycheck support
(use-package flycheck-clj-kondo
:after (clojure-mode)
:if (executable-find "clj-kondo"))
(use-package cider
:commands (cider-mode cider-jack-in cider-jack-in-clojurescript)
:custom
(cider-known-endpoints
'(("local" "localhost" "4005")))
(cider-prompt-for-symbol nil)
(general-def cider-mode-map "C-c t" cider-test-commands-map)
:hook ((clojure-mode . cider-mode)
(clojurescript-mode . cider-mode)
(clojurec-mode . cider-mode))
:general
(cider-stacktrace-mode-map "SPC" leader-map)
('normal cider-mode-map "M-." #'cider-find-var)
(cider-repl-mode-map "C-c C-l" #'cider-repl-clear-buffer))
(provide 'init-clojure)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Nicer minibuffer completion
;; First Selectrum, which provides the core incremental minibuffer completion engine
@ -63,6 +65,7 @@
(use-package consult
:general
([remap switch-to-buffer] #'consult-buffer)
([remap imenu] #'consult-imenu))
([remap imenu] #'consult-imenu)
("C-c p" #'consult-yank))
(provide 'init-completion)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; A neat dashboard when you open Emacs
(use-package dashboard
:demand t

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Fix Emacs' bad defaults
;; Save backups and autosaves in a centralized place

View File

@ -1,8 +1,21 @@
;; -*- lexical-binding: t; -*-
;; Make Dired even better
(use-package dired
:straight (:type built-in)
:config
(evil-collection-dired-setup))
(defun dired-find-file-current-dir ()
(interactive)
(let ((default-directory (dired-current-directory)))
(call-interactively #'find-file)))
(defun dired-do-rename-current-dir ()
(interactive)
(let ((default-directory (dired-current-directory)))
(call-interactively #'dired-do-rename)))
(evil-collection-dired-setup)
:general
(dired-mode-map [remap find-file] #'dired-find-file-current-dir
[remap dired-do-rename] #'dired-do-rename-current-dir))
;; Add a toggleable dired sidebar
(use-package dired-sidebar

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Utilities to manage dotfiles
(defun find-init-file ()
(interactive)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; General text editing configuration
;; Better isearch
@ -56,6 +58,17 @@
;; Automagical indent
(use-package aggressive-indent
:hook (prog-mode . aggressive-indent-mode))
:hook ((lisp-mode . aggressive-indent-mode)
(emacs-lisp-mode . aggressive-indent-mode)
(clojure-mode . aggressive-indent-mode)))
;; Highlight indent level for whitespace-sensitive languages
(use-package highlight-indent-guides
:commands highlight-indent-guides-mode
:custom
(highlight-indent-guides-method 'character)
(highlight-indent-guides-auto-character-face-perc 7)
(highlight-indent-guides-responsive 'stack)
(highlight-indent-guides-auto-stack-character-face-perc 10))
(provide 'init-editing)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
(use-package eshell
:straight (:type built-in)
:config

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Set up Vim keybindings with evil-mode
(use-package evil
:init

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; File-related configuration
(leader-def-key

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Magit!
(use-package magit
:commands (magit-status

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Emacs has fanstastic built-in help features, but they could be more convenient
(use-package info

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; IDE features
;; Company-mode provides inline autocompletion

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Load up general.el, which-key, and set up keybindings for built-ins
(use-package general
:config

View File

@ -0,0 +1,19 @@
;; -*- lexical-binding: t; -*-
;; Elisp utilities
(defun make-process-sentinel (success err)
"Makes a process sentinel that calls `success` on success and `err` on error"
(lambda (proc event)
(cond ((string-match-p "finished" event) (funcall success))
(t (funcall err)))))
(defun make-success-err-msg-sentinel (buf success-msg err-msg &optional kill-on-err)
(make-process-sentinel
(lambda ()
(message success-msg)
(kill-buffer buf))
(lambda ()
(message err-msg)
(when kill-on-err
(kill-buffer buf)))))
(provide 'init-lib)

View File

@ -1,5 +1,11 @@
;; -*- lexical-binding: t; -*-
;; Profiling startup time
(use-package esup
:commands esup)
:commands esup
:custom
(esup-user-init-file (file-truename
(expand-file-name "init.el"
user-emacs-directory))))
(provide 'init-profiler)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Project management
(use-package projectile
:config

View File

@ -0,0 +1,55 @@
;; -*- lexical-binding: t; -*-
;; Python configuration
(use-package python
:defer t
:straight (:type built-in)
:config
(add-hook 'python-mode-hook #'highlight-indent-guides-mode)
;; Redefine the python-mypy flycheck checker to account for projectile-compilation-dir
(flycheck-define-checker python-mypy
"Mypy syntax and type checker. Requires mypy>=0.580.
See URL `http://mypy-lang.org/'."
:command ("mypy"
"--show-column-numbers"
(config-file "--config-file" flycheck-python-mypy-config)
(option "--cache-dir" flycheck-python-mypy-cache-dir)
source-original)
:error-patterns
((error line-start (file-name) ":" line (optional ":" column)
": error:" (message) line-end)
(warning line-start (file-name) ":" line (optional ":" column)
": warning:" (message) line-end)
(info line-start (file-name) ":" line (optional ":" column)
": note:" (message) line-end))
:modes python-mode
;; Ensure the file is saved, to work around
;; https://github.com/python/mypy/issues/4746.
:predicate flycheck-buffer-saved-p
:working-directory (lambda (checker)
(or (projectile-compilation-dir)
default-directory))))
;; pyvenv to track virtual environments
(use-package pyvenv
:defer 3
:config
(pyvenv-mode)
(pyvenv-tracking-mode))
;; pyenv to track Python version
(use-package pyenv-mode
:defer t)
;; LSP using Microsoft's pyright language server
(use-package lsp-pyright
:hook (python-mode . (lambda ()
(require 'lsp-pyright)
(lsp-deferred)))
:custom
(lsp-pyright-use-library-code-for-types t)
:general
(python-mode-map "C-c C-d" #'lsp-describe-thing-at-point))
(provide 'init-python)

View File

@ -0,0 +1,204 @@
;; -*- lexical-binding: t; -*-
;; A handy package for running external commands
(use-package run-command
:straight (run-command :host github :repo "bard/emacs-run-command"
:fork (:host github :repo "jdormit/emacs-run-command" :branch "master"))
:init
(defvar-local run-command-local-commands nil)
(put 'run-command-local-commands 'safe-local-variable (lambda (_) t))
(defvar-local run-command-project-local-commands nil)
(put 'run-command-project-local-commands 'safe-local-variable (lambda (_) t))
:config
(defun run-command-recipe-terraform ()
(when (directory-files default-directory
nil
(rx (one-or-more any)
".tf"
eol))
(list
(list :command-name "init"
:command-line "terraform init")
(list :command-name "plan"
:command-line "terraform plan")
(list :command-name "apply"
:command-line "terraform apply")
(list :command-name "destroy"
:command-line "terraform destroy"))))
(defun run-command-recipe-local ()
(when run-command-local-commands
(mapcar (cl-function
(lambda ((name . spec))
(let ((name (if (symbolp name) (symbol-name name) name)))
(list :command-name name
:command-line spec))))
run-command-local-commands)))
(defun run-command-recipe-package-json--get-scripts (package-json-file)
"Extract NPM scripts from `package-json-file'."
(with-temp-buffer
(insert-file-contents package-json-file)
(let* ((json-data (json-parse-buffer))
(script-hash (gethash "scripts" json-data))
(scripts '()))
(when script-hash
(maphash (lambda (key _value) (push key scripts)) script-hash))
scripts)))
(defun run-command-recipe-package-json ()
(when-let* ((project-dir
(locate-dominating-file default-directory "package.json"))
(scripts
(run-command-recipe-package-json--get-scripts (concat project-dir "package.json")))
(script-runner
(if (file-exists-p (concat project-dir "yarn.lock")) "yarn" "npm")))
(mapcar (lambda (script)
(list :command-name script
:command-line (concat script-runner " run " script)
:display script
:working-dir project-dir))
scripts)))
(defun makefile-target-list-default (makefile)
"Return the target list for MAKEFILE by parsing it."
(let (targets)
(with-temp-buffer
(insert-file-contents makefile)
(goto-char (point-min))
(while (re-search-forward "^\\([^: \n]+\\) *:\\(?: \\|$\\)" nil t)
(let ((str (match-string 1)))
(unless (string-match "^\\." str)
(push str targets)))))
(nreverse targets)))
(defun run-command-recipe-makefile ()
(when-let* ((project-dir (locate-dominating-file default-directory "Makefile"))
(makefile (concat project-dir "Makefile"))
(targets (makefile-target-list-default makefile)))
(mapcar (lambda (target)
(list :command-name target
:command-line (concat "make " target)
:display target
:working-dir project-dir))
targets)))
(defun run-command-recipe-project ()
(when (projectile-project-root)
(mapcar (lambda (cmd)
(when-let ((cmd-val (symbol-value
(intern
(format "projectile-project-%s-cmd" cmd)))))
(list :command-name cmd
:command-line cmd-val
:working-dir (projectile-compilation-dir))))
'("test" "run" "compilation" "configure" "install" "package"))))
(defun run-command-recipe-project-local ()
(when (and run-command-project-local-commands (projectile-project-root))
(mapcar (cl-function
(lambda ((name . spec))
(let ((name (if (symbolp name) (symbol-name name) name)))
(list :command-name name
:command-line spec
:working-dir (projectile-compilation-dir)))))
run-command-project-local-commands)))
(defun run-command-recipe-executables ()
(let* ((buffer-file (buffer-file-name))
(executable-p (and buffer-file (file-executable-p buffer-file))))
(list
(when executable-p
(list
:command-name "run-buffer-file"
:command-line buffer-file
:display "Run this buffer's file"))
(when (and executable-p (executable-find "entr"))
(list
:command-name "run-buffer-file-watch"
:command-line (format "echo %s | entr -c /_" buffer-file)
:display "Run this buffer's file (re-run on each save)")))))
(defun run-command-recipe-obelix ()
(when-let* ((config (or (locate-dominating-file default-directory "obelix.json")
(locate-dominating-file default-directory "obelix.edn")))
(dir (file-name-directory config)))
(list
(list :command-name "build"
:command-line "obelix build"
:working-dir dir)
(list :command-name "serve"
:command-line "obelix serve"
:working-dir dir))))
(defun run-command-recipe-kustomize ()
(when-let* ((kustomization (locate-dominating-file default-directory "kustomization.yaml"))
(dir (file-name-directory kustomization)))
(list
(list :command-name "build"
:command-line "kustomize build --enable_alpha_plugins"
:working-dir dir))))
(defun run-command-recipe-sops ()
(when (save-excursion
(goto-char (point-min))
(search-forward-regexp "sops:" nil t))
(list
(list :command-name "edit"
:command-line (format "sops %s" (buffer-file-name))))))
(defun run-command-recipe-pytest ()
(when (and (derived-mode-p 'python-mode)
(= 0 (call-process "python" nil nil nil "-c" "import pytest")))
(let ((test-file-p (string-match-p "test" (or (buffer-file-name) ""))))
(list
(when (and (projectile-project-root)
(file-exists-p (concat (file-name-as-directory (projectile-project-root))
"tests")))
(list :command-name "test all"
:command-line "pytest tests"
:working-dir (projectile-project-root)))
(when test-file-p
(list :command-name "test this file"
:command-line (format "pytest %s" (buffer-file-name))))
(when (and test-file-p (python-info-current-defun))
(list :command-name "test this function"
:command-line (format "pytest %s::%s"
(buffer-file-name)
(replace-regexp-in-string
"\\."
"::"
(python-info-current-defun)))))))))
(defun run-command-recipe-web-ext ()
(when-let* ((_ (executable-find "web-ext"))
(manifest (locate-dominating-file default-directory "manifest.json"))
(dir (file-name-directory manifest)))
(list
(list :command-name "run"
:command-line "web-ext run"
:working-dir dir)
(list :command-name "build"
:command-line "web-ext build"
:working-dir dir))))
:general
(leader-map "\"" #'run-command)
(run-command-term-minor-mode-map [remap recompile] #'run-command-term-recompile)
:custom
(run-command-run-method 'async-shell)
(run-command-recipes '(run-command-recipe-terraform
run-command-recipe-local
run-command-recipe-package-json
run-command-recipe-makefile
run-command-recipe-project
run-command-recipe-project-local
run-command-recipe-executables
run-command-recipe-obelix
run-command-recipe-kustomize
run-command-recipe-sops
run-command-recipe-pytest
run-command-recipe-web-ext)))
(provide 'run-command)

View File

@ -0,0 +1,7 @@
;; -*- lexical-binding: t; -*-
;; Configuration as code!
(use-package terraform-mode
:mode "\\.tf\\'")
(provide 'init-terraform)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Don't show ugly graphical UI elements
(when (window-system)
(tool-bar-mode -1)

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Tree-shaped undos
(use-package undo-tree
:demand t

View File

@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
;; Window-related configuration
;; winum-mode allows selecting windows by number

View File

@ -0,0 +1,9 @@
;; -*- lexical-binding: t; -*-
;; YAML - literally the worst but still holds an important place in my life
(use-package yaml-mode
:mode ("\\.yaml\\'" "\\.yml\\'")
:config
(add-hook 'yaml-mode-hook #'highlight-indent-guides-mode))
(provide 'init-yaml)

View File

@ -1,10 +1,21 @@
(setq lexical-binding t)
(setq gc-cons-threshold 100000000)
;; -*- lexical-binding: t; -*-
;; Some startup time optimizations stolen from Doom emacs
(setq gc-cons-threshold most-positive-fixnum ; 2^61 bytes
gc-cons-percentage 0.6)
(defvar file-name-handler-alist-backup file-name-handler-alist)
(setq file-name-handler-alist nil)
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold 16777216 ; 16mb
gc-cons-percentage 0.1
file-name-handler-alist file-name-handler-alist-backup)))
;; Bootstrap the straight.el package manager
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(expand-file-name "straight/repos/straight.el/bootstrap.el"
user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
@ -42,6 +53,7 @@
(require 'init-evil)
(require 'init-keybindings)
(require 'init-auth)
(require 'init-lib)
(require 'init-profiler)
(require 'init-built-ins)
(require 'init-dashboard)
@ -58,6 +70,12 @@
(require 'init-ide)
(require 'init-eshell)
(require 'init-help)
(require 'init-python)
(require 'init-clojure)
(require 'init-yaml)
(require 'init-terraform)
(require 'init-run-command)
(require 'init-aws)
;; Load the custom file
(when (file-exists-p custom-file)