diff --git a/old-emacs/.emacs.tiny.el b/old-emacs/.emacs.tiny.el deleted file mode 100644 index dbb057d..0000000 --- a/old-emacs/.emacs.tiny.el +++ /dev/null @@ -1,41 +0,0 @@ -;; package setup -(require 'package) -(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/")) -(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) -(package-initialize) -(unless (package-installed-p 'use-package) - (package-refresh-contents) - (package-install 'use-package)) -(eval-when-compile (require 'use-package)) -(setq use-package-always-ensure t) - -;; evil mode -(use-package evil - :init - (setq evil-want-keybinding nil) - :config - (evil-mode 1) - (setq evil-want-fine-undo t)) -(use-package evil-collection - :after (evil) - :config - (evil-collection-init)) - -;; which-key -(use-package which-key - :config - (which-key-mode)) - -;; ivy -(use-package counsel - :config - (ivy-mode 1) - (setq ivy-wrap t)) -(use-package ivy-hydra - :after counsel) - -;; magit -(use-package magit - :commands (magit-status magit-blame magit-find-file)) -(use-package evil-magit - :after magit) diff --git a/old-emacs/eshell/alias b/old-emacs/eshell/alias deleted file mode 100644 index bdbecff..0000000 --- a/old-emacs/eshell/alias +++ /dev/null @@ -1,8 +0,0 @@ -alias root cd (projectile-project-root) -alias php-debug php -d xdebug.remote_enable=on -d xdebug.remote_host=127.0.0.1 -d xdebug.remote_port=9000 -d xdebug.remote_handler=dbgp -d xdebug.idekey=geben -d xdebug.remote_autostart=On $* -alias kns kubens $* -alias k kubectl $* -alias kctx kubectx $* -alias sortpom mvn com.github.ekryd.sortpom:sortpom-maven-plugin:sort -Dsort.keepBlankLines -Dsort.sortDependencies=scope,groupId,artifactId -Dsort.createBackupFile=false $* -alias helm /usr/local/bin/helm $* -alias tf terraform $* diff --git a/old-emacs/init.el b/old-emacs/init.el deleted file mode 100644 index eeaa593..0000000 --- a/old-emacs/init.el +++ /dev/null @@ -1,35 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;; If ~/.emacs.d/config/base.el exists, just load it. Otherwise, -;; first bootstrap Straight and load Org to make sure we end up with -;; the right Org version, then tangle ~/.emacs.d/init.org to -;; ~/.emacs.d/config/base.el - -(defvar init-org-file (expand-file-name "~/.emacs.old/init.org")) -(defvar config-base-file (expand-file-name "~/.emacs.old/config/base.el")) - -(when (not (file-exists-p "~/.emacs.old/config")) - (make-directory "~/.emacs.old/config")) - -(when (not (file-exists-p config-base-file)) - (message "Bootstrapping init file...") - (defvar bootstrapping-init t) - (defvar bootstrap-version) - (let ((bootstrap-file - (expand-file-name "straight/repos/straight.el/bootstrap.el" - user-emacs-directory)) - (bootstrap-version 5)) - (unless (file-exists-p bootstrap-file) - (with-current-buffer - (url-retrieve-synchronously - "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" - 'silent 'inhibit-cookies) - (goto-char (point-max)) - (eval-print-last-sexp))) - (load bootstrap-file nil 'nomessage)) - - (straight-use-package 'org-plus-contrib) - (require 'org) - (org-babel-tangle-file init-org-file)) - -(load-file config-base-file) diff --git a/old-emacs/init.el~ b/old-emacs/init.el~ deleted file mode 100644 index 4af67fa..0000000 --- a/old-emacs/init.el~ +++ /dev/null @@ -1,35 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;; If ~/.emacs.d/config/base.el exists, just load it. Otherwise, -;; first bootstrap Straight and load Org to make sure we end up with -;; the right Org version, then tangle ~/.emacs.d/init.org to -;; ~/.emacs.d/config/base.el - -(defvar init-org-file (expand-file-name "~/.emacs.d/init.org")) -(defvar config-base-file (expand-file-name "~/.emacs.d/config/base.el")) - -(when (not (file-exists-p "~/.emacs.d/config")) - (make-directory "~/.emacs.d/config")) - -(when (not (file-exists-p config-base-file)) - (message "Bootstrapping init file...") - (defvar bootstrapping-init t) - (defvar bootstrap-version) - (let ((bootstrap-file - (expand-file-name "straight/repos/straight.el/bootstrap.el" - user-emacs-directory)) - (bootstrap-version 5)) - (unless (file-exists-p bootstrap-file) - (with-current-buffer - (url-retrieve-synchronously - "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" - 'silent 'inhibit-cookies) - (goto-char (point-max)) - (eval-print-last-sexp))) - (load bootstrap-file nil 'nomessage)) - - (straight-use-package 'org-plus-contrib) - (require 'org) - (org-babel-tangle-file init-org-file)) - -(load-file config-base-file) diff --git a/old-emacs/init.org b/old-emacs/init.org deleted file mode 100755 index 7c246a1..0000000 --- a/old-emacs/init.org +++ /dev/null @@ -1,7119 +0,0 @@ -#+PROPERTY: header-args :results silent -#+PROPERTY: header-args:emacs-lisp :lexical t :tangle ~/.emacs.d/config/base.el - -This is a literate init file holding my Emacs configuration. It is -initially loaded by a [[file:init.el][bootstrap file]] that lives at ~/.emacs.d/init.el. - -* Prelude -Enables lexical binding for everything in init.el: -#+BEGIN_SRC emacs-lisp - ;;; -*- lexical-binding: t; -*- -#+END_SRC - -** Garbage collection -Some GC tweaks [[https://github.com/hlissner/doom-emacs/blob/develop/docs/faq.org#how-does-doom-start-up-so-quickly]["borrowed" from Doom emacs]]. - -Turn off GC during init and restore it afterwards: -#+BEGIN_SRC emacs-lisp - (setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6) - - (add-hook 'emacs-startup-hook - (lambda () - (setq gc-cons-threshold 100000000 - gc-cons-percentage 0.1))) -#+END_SRC - -Also suppress GC for 1 second after the minibuffer is active to avoid stuttering autocompletion and other GC hangups: -#+BEGIN_SRC emacs-lisp - (defun defer-garbage-collection () - (setq gc-cons-threshold most-positive-fixnum)) - - (defun restore-garbage-collection () - (run-at-time - 1 nil (lambda () (setq gc-cons-threshold 100000000)))) - - (add-hook 'minibuffer-setup-hook #'defer-garbage-collection) - (add-hook 'minibuffer-exit-hook #'restore-garbage-collection) -#+END_SRC - -** Unset file-handler-alist during initialization -Another optimization from [[https://github.com/hlissner/doom-emacs/blob/develop/docs/faq.org#how-does-doom-start-up-so-quickly][Doom Emacs]]. -#+BEGIN_SRC emacs-lisp - (defvar file-name-handler-alist-backup file-name-handler-alist) - (setq file-name-handler-alist nil) - (add-hook 'emacs-startup-hook - (lambda () - (setq file-name-handler-alist file-name-handler-alist-backup))) -#+END_SRC - -** Variables -#+BEGIN_SRC emacs-lisp - (setq vc-follow-symlinks t - frame-resize-pixelwise t - tab-always-indent 'complete - enable-recursive-minibuffers t - read-process-output-max (* 1024 1024) - bookmark-save-flag 1) - (setq-default indent-tabs-mode nil) -#+END_SRC - -* Default directory -#+BEGIN_SRC emacs-lisp - (cd "~") -#+END_SRC - -* Packages -Load [[https://github.com/raxod502/straight.el][straight.el]] to manage package installation: -#+BEGIN_SRC emacs-lisp - (defvar bootstrap-version) - (unless (boundp 'bootstrapping-init) - (let ((bootstrap-file - (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) - (bootstrap-version 5)) - (unless (file-exists-p bootstrap-file) - (with-current-buffer - (url-retrieve-synchronously - "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" - 'silent 'inhibit-cookies) - (goto-char (point-max)) - (eval-print-last-sexp))) - (load bootstrap-file nil 'nomessage))) -#+END_SRC - -`use-package` is a macro that simplifies installing and loading packages. -#+BEGIN_SRC emacs-lisp - (straight-use-package 'use-package) - (setq straight-use-package-by-default t) -#+END_SRC - -** Utility functions -#+BEGIN_SRC emacs-lisp - (defun find-library-readme (library) - (interactive (list (read-library-name))) - (let* ((dir (file-name-directory (file-truename (find-library-name library)))) - (doc (car (directory-files dir t "\\(readme\\|README\\)\\..*")))) - (if (not doc) - (error "No README found") - (find-file doc) - (when (eq major-mode 'markdown-mode) - (markdown-view-mode))))) -#+END_SRC - -* Benchmarking -`benchmark-init` does what it says on the box. This sets it up to benchmark my init time and then disable benchmarking after init completes. -#+BEGIN_SRC emacs-lisp - (use-package benchmark-init - :config - (add-hook 'after-init-hook 'benchmark-init/deactivate)) -#+END_SRC - -* General -Better keybinding. -#+BEGIN_SRC emacs-lisp - (use-package general - :init - (setq general-override-states '(insert - emacs - hybrid - normal - visual - motion - operator - replace))) -#+END_SRC - -* Which-key -`which-key` makes keybindings discoverable. -#+BEGIN_SRC emacs-lisp - (use-package which-key - :config - (which-key-mode)) -#+END_SRC - -This function defines a prefix group for `which-key` so that it doesn't display `prefix`. -#+BEGIN_SRC emacs-lisp - (defun jdormit/define-prefix (binding name) - (which-key-add-key-based-replacements - (concat leader " " binding) - name) - (which-key-add-key-based-replacements - (concat "," " " binding) - name)) -#+END_SRC - -* Evil Mode -Because I like modal editing and dislike RSI. -#+BEGIN_SRC emacs-lisp - (use-package evil - :init - (setq evil-want-keybinding nil) - :config - (evil-mode 1)) -#+END_SRC - -Make undo not undo paragraphs at a time: - -#+BEGIN_SRC emacs-lisp - (setq evil-want-fine-undo t) -#+END_SRC - -Add a convenience function for making buffer-local ex-commands: -#+BEGIN_SRC emacs-lisp - (defun evil-ex-define-local-cmd (cmd function) - (set (make-local-variable 'evil-ex-commands) (copy-tree evil-ex-commands)) - (evil-ex-define-cmd cmd function)) -#+END_SRC - - -** evil-collection -A collection of evil bindings for various modes -#+BEGIN_SRC emacs-lisp - (use-package evil-collection - :after (evil) - :hook ((after-init . evil-collection-init)) - :config - (setq evil-collection-company-use-tng nil)) -#+END_SRC - -** leader key -Use the spacebar as a leader key in evil-mode's normal state and in various other modes: -#+BEGIN_SRC emacs-lisp - (defconst leader "SPC") - (general-define-key - :keymaps 'override - :states '(normal visual motion) - "SPC" nil) - (general-create-definer leader-def-key - :keymaps 'override - :states '(normal visual motion) - :prefix leader - :prefix-map 'leader-map) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "?" "help") - (leader-def-key "?" help-map) -#+END_SRC - -** evil-snipe -#+BEGIN_SRC emacs-lisp - (use-package evil-snipe - :after (evil) - :config - (evil-snipe-mode 1) - (evil-snipe-override-mode 1) - (add-to-list 'evil-snipe-disabled-modes 'dired-mode) - (add-to-list 'evil-snipe-disabled-modes 'structlog-mode) - (with-eval-after-load 'magit - (add-hook 'magit-mode-hook 'turn-off-evil-snipe-override-mode)) - (with-eval-after-load 'prodigy - (add-hook 'prodigy-mode-hook 'turn-off-evil-snipe-mode)) - (with-eval-after-load 'pass - (add-hook 'pass-mode-hook 'turn-off-evil-snipe-mode))) -#+END_SRC - -** evil-commentary -Adds Evil commands to comment out lines of code: -#+BEGIN_SRC emacs-lisp - (use-package evil-commentary - :after (evil) - :hook ((prog-mode . evil-commentary-mode))) -#+END_SRC -** Additional keybindings -#+BEGIN_SRC emacs-lisp - (general-def 'normal "zM" #'hs-hide-level :keymaps 'override) - (general-def 'normal "z=" #'text-scale-increase :keymaps 'override) - (general-def 'normal "z-" #'text-scale-decrease :keymaps 'override) - (general-def 'normal "z0" #'text-scale-adjust :keymaps 'override) - (general-def 'normal view-mode-map "0" nil :keymaps 'override) - (general-def 'normal prodigy-view-mode-map "0" nil :keymaps 'override) - (general-def 'normal messages-buffer-mode-map "SPC" leader-map :keymaps 'override) -#+END_SRC - -* Hydra -[[https://github.com/abo-abo/hydra][Hydra]]s are convenient keybinding menus. -#+BEGIN_SRC emacs-lisp - (use-package hydra - :defer t) -#+END_SRC - -* Syncthing -I put lots of stuff in Syncthing, but the actual folder location -differs on my different computers. This function resolves to the -Syncthing directory: -#+BEGIN_SRC emacs-lisp - (defcustom syncthing-path (expand-file-name "~/Sync") - "The absolute path to the Syncthing directory" - :type 'directory) - - (defun syncthing-directory (&optional path) - (f-join syncthing-path (s-chop-prefix (f-path-separator) (or path "")))) -#+END_SRC - -* Emacs Lisp -** Packages -Some helpful ELisp packages: -- [[https://github.com/kiwanami/emacs-deferred][deferred]] is an async API library -- [[https://github.com/magnars/s.el][s.el]] is a string manipulation library -- [[https://github.com/magnars/dash.el][dash.el]] is a list manipulation library -- [[https://github.com/rejeep/f.el][f.el]] is a file manipulation library -- [[https://github.com/tkf/emacs-request][request]] is an HTTP library -#+BEGIN_SRC emacs-lisp - (use-package deferred - :commands (deferred:next - deferred:nextc - deferred:error - deferred:cancel - deferred:watch - deferred:wait - deferred:$ - deferred:loop - deferred:parallel - deferred:earlier - deferred:call - deferred:apply - deferred:process - deferred:process-buffer - deferred:wait-idle - deferred:url-retrieve - deferred:url-get - deferred:url-post - deferred:new - deferred:succeed - deferred:fail - deferred:callback - deferred:callback-post - deferred:errorback - deferred:errorback-post - deferred:try - deferred:timeout - deferred:process)) - (use-package s - :defer t - :init - (add-hook 'emacs-startup-hook (lambda () (require 's))) - :config - (defun camel-case (&optional arg) - (interactive "P") - (let* ((bounds (bounds-of-thing-at-point 'symbol)) - (word (buffer-substring (car bounds) (cdr bounds))) - (camel (if arg (s-upper-camel-case word) - (s-lower-camel-case word)))) - (delete-region (car bounds) (cdr bounds)) - (insert camel)))) - (use-package dash - :defer t - :init - (add-hook 'emacs-startup-hook (lambda () (require 'dash)))) - (use-package dash-functional - :defer t - :init - (add-hook 'emacs-startup-hook (lambda () (require 'dash-functional)))) - (use-package f - :defer t - :init - (add-hook 'emacs-startup-hook (lambda () (require 'f))) - (autoload 'f-join "f")) - (use-package request - :commands (request request-deferred)) - (use-package ht - :defer t) -#+END_SRC - -** Editing Elisp -#+BEGIN_SRC emacs-lisp - (general-def '(normal motion) emacs-lisp-mode-map "C-c C-c" #'eval-defun :keymaps 'override) - (general-def '(normal motion insert) lisp-interaction-mode-map "C-c C-c" #'eval-print-last-sexp :keymaps 'override) - (add-hook 'ielm-mode-hook 'smartparens-strict-mode) -#+END_SRC - -** Load path -For machine or user specific libraries: -#+BEGIN_SRC emacs-lisp - (add-to-list 'load-path (expand-file-name "~/site-lisp")) -#+END_SRC - -And for global ones: -#+BEGIN_SRC emacs-lisp - (add-to-list 'load-path "/usr/local/share/emacs/site-lisp") -#+END_SRC - -** Utilities -Reading a file as a string: -#+BEGIN_SRC emacs-lisp - (defun read-file (path) - "Returns the contents of the file as a string" - (with-temp-buffer - (insert-file-contents path) - (buffer-string))) -#+END_SRC - -Opening a file as sudo: -#+BEGIN_SRC emacs-lisp - (defun sudo-find-file (file-name) - "Like find file, but opens the file as root." - (interactive "F") - (let ((tramp-file-name (concat "/sudo::" (expand-file-name file-name)))) - (find-file tramp-file-name))) - -#+END_SRC - -Recursive =assoc= for nested alists: -#+BEGIN_SRC emacs-lisp - (defun assoc-recursive (alist &rest keys) - "Recursively find KEYs in ALIST." - (while keys - (setq alist (cdr (assoc (pop keys) alist)))) - alist) -#+END_SRC - -Format a millis timestamp into human-readable form: -#+BEGIN_SRC emacs-lisp - (defun format-epoch-millis (millis) - (interactive "nTimestamp: ") - (message (format-time-string "%F %r" (/ millis 1000)))) -#+END_SRC - -The same but for seconds: -#+BEGIN_SRC emacs-lisp - (defun format-epoch-seconds (seconds) - (interactive "nTimestamp: ") - (message (format-time-string "%F %r" seconds))) -#+END_SRC - -Checking if a buffer contains a string: -#+BEGIN_SRC emacs-lisp - (defun buffer-contains-substring (string) - (save-excursion - (save-match-data - (goto-char (point-min)) - (search-forward string nil t)))) -#+END_SRC - -Pretty-print JSON: -#+BEGIN_SRC emacs-lisp - (defun pprint-json (raw-json) - (with-temp-buffer - (insert raw-json) - (json-pretty-print (point-min) (point-max)) - (buffer-substring (point-min) (point-max)))) -#+END_SRC - -Load environment variables into Emacs from a shell script: -#+BEGIN_SRC emacs-lisp - (cl-defun extract-vars-from-env-file (file &key dir) - "Extracts an alist of variable name to value from - a bash script that exports environment variables." - (let ((file (expand-file-name file)) - (var-re "\\(.+?\\)=\\(.+\\)$") - (env '())) - (with-temp-buffer - (cd (expand-file-name (or dir (file-name-directory file)))) - (insert (shell-command-to-string (concat "source " - (shell-quote-argument file) - " > /dev/null && env"))) - (goto-char (point-min)) - (save-match-data - (while (re-search-forward var-re nil t) - (push (cons (match-string 1) (match-string 2)) env)))) - env)) - - (defun source-env-file (file) - (interactive "fFile: \n") - (let ((env (extract-vars-from-env-file file))) - (dolist (binding env) - (setenv (car binding) (cdr binding))))) - - (cl-defmacro with-env-from-file (file &rest body) - (declare (indent 1)) - (let ((env-var (make-symbol "the-env")) - (path-var (make-symbol "the-path"))) - `(let* ((,env-var (extract-vars-from-env-file ,file)) - (,path-var (assoc "PATH" ,env-var)) - (exec-path - (if ,path-var - (append (split-string (cdr ,path-var) ":") exec-path) - exec-path)) - (process-environment - (append - (mapcar - (lambda (elt) (format "%s=%s" (car elt) (cdr elt))) - ,env-var) - process-environment))) - ,@body))) - - (cl-defun call-with-env-from-file (file callback &key dir) - (let* ((env (extract-vars-from-env-file file :dir dir)) - (path (assoc "PATH" env)) - (exec-path - (if path - (append (split-string (cdr path) ":") exec-path) - exec-path)) - (process-environment - (append (mapcar (lambda (elt) (format "%s=%s" (car elt) (cdr elt))) env) - process-environment))) - (funcall callback))) - - (defmacro with-env (env &rest body) - (declare (indent 1)) - `(let* ((process-environment - (append - (mapcar - (lambda (elt) (format "%s=%s" (car elt) (cdr elt))) - ,env) - process-environment))) - ,@body)) -#+END_SRC - -Convenience macro to run some code in a particular default-directory: -#+BEGIN_SRC emacs-lisp - (defmacro with-default-directory (dir &rest body) - (declare (indent 1)) - `(let ((default-directory ,dir)) - ,@body)) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (defun random-alnum (&optional n) - (let* ((n-chars (or n 1)) - (alnum "abcdefghijklmnopqrstuvwxyz0123456789") - (result "")) - (dotimes (_ n-chars result) - (let ((i (% (abs (random)) (length alnum)))) - (setq result - (concat result (substring alnum i (1+ i)))))))) -#+END_SRC - -A handy function to colorize a buffer with ANSI escape characters in it: -#+BEGIN_SRC emacs-lisp - (defun ansi-color (&optional begin end) - (interactive) - (let ((begin (or begin (point-min))) - (end (or end (point-max))) - (inhibit-read-only t)) - (ansi-color-apply-on-region begin end))) -#+END_SRC - -** Persisting variables between session -The idea behind this is pretty simple - variables get persisted in ~/.emacs.d/ as a plist of (variable-name variable-value). - -#+BEGIN_SRC emacs-lisp - (defvar persisted-vars-file "~/.emacs.d/persisted-vars") -#+END_SRC - -This function retrieves the plist of persisted variables or nil if it doesn't exist: -#+BEGIN_SRC emacs-lisp - (defun get-persisted-plist () - (let ((file (expand-file-name persisted-vars-file))) - (when (file-exists-p file) - (let ((vars-plist-str (read-file file))) - (unless (string= vars-plist-str "") - (car (read-from-string vars-plist-str))))))) -#+END_SRC - -This function retrieves a persisted variable: -#+BEGIN_SRC emacs-lisp - (defun get-persisted-var (var-name) - "Retrieves the value of persisted variable `var-name`, or nil if not found" - (let ((vars-plist (get-persisted-plist))) - (when vars-plist - (plist-get vars-plist var-name)))) -#+END_SRC - -And this function persists a variable: -#+BEGIN_SRC emacs-lisp - (defun persist-variable (var-name value) - (let ((file (expand-file-name persisted-vars-file)) - (vars-plist (get-persisted-plist))) - (if vars-plist - (progn - (plist-put vars-plist var-name value) - (write-region - (prin1-to-string vars-plist) nil file)) - (let ((vars-plist `(,var-name ,value))) - (write-region - (prin1-to-string vars-plist) nil file))))) -#+END_SRC - -** Process handling -Some utilities for calling out to other processes. -#+BEGIN_SRC emacs-lisp - (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))))) -#+END_SRC - -A function to call a process passing some string as stdin and returning the process output: -#+BEGIN_SRC emacs-lisp - (defun make-process-fn (program &rest args) - "Returns a function that, when called, call `program` with arguments `args`, - passing the function argument as stdin" - (lambda (&optional input) - (with-temp-buffer - (if input - (progn - (insert input) - (apply #'call-process-region (point-min) (point-max) program t t nil args)) - (apply #'call-process program nil t nil args)) - (buffer-substring-no-properties (point-min) (point-max))))) -#+END_SRC - -The same function but for commands that need to run in a shell: -#+BEGIN_SRC emacs-lisp - (defun make-shell-fn (program &rest args) - "Returns a function that, when called, calls `program` in a shell - with arguments `args`, passing the function argument as stdin" - (lambda (&optional input) - (let ((cmd (combine-and-quote-strings `(,program ,@args)))) - (with-temp-buffer - (if input - (progn - (insert input) - (call-shell-region (point-min) (point-max) cmd t t)) - (call-process-shell-command cmd nil t)) - (buffer-substring-no-properties (point-min) (point-max)))))) -#+END_SRC - -Running a shell command as sudo: -#+BEGIN_SRC emacs-lisp - (defun sudo-shell-command (command) - (with-temp-buffer - (cd "/sudo::/") - (shell-command command))) -#+END_SRC - -** Buffer switch hooks -I want to be able to run code whenever I switch to a buffer running certain modes. The code to run is stored in a alist mapping mode names to lists of code to run (stored as a raw data structure to be eval'ed): -#+BEGIN_SRC emacs-lisp - (defvar buffer-mode-hooks '()) -#+END_SRC - -To add a new hook, push the code to run onto the correct list: -#+BEGIN_SRC emacs-lisp - (defun add-buffer-mode-hook (mode fn) - (if-let ((existing-entry (assoc mode buffer-mode-hooks))) - (push fn (cdr existing-entry)) - (let ((new-entry `(,mode . (,fn)))) - (push new-entry buffer-mode-hooks)))) -#+END_SRC - -Whenever the buffer changes, look up the major-mode to see if there is any code to run: -#+BEGIN_SRC emacs-lisp - (defun run-buffer-mode-hooks () - (when-let ((entry (assoc major-mode buffer-mode-hooks))) - (dolist (fn (cdr entry)) - (funcall fn)))) - - (add-hook 'buffer-list-update-hook #'run-buffer-mode-hooks) -#+END_SRC - -** Aliases -#+BEGIN_SRC emacs-lisp - (defalias 'doc 'describe-symbol) -#+END_SRC - -** Miscellaneous -#+BEGIN_SRC emacs-lisp - (setq warning-suppress-types - '((undo discard-info))) -#+END_SRC - -* Org Mode -Notes, agenda, calendar, blogging, journaling, etc. - -Loaded early to [[https://github.com/raxod502/straight.el#the-wrong-version-of-my-package-was-loaded][avoid a version clash]]. - -First, a function to get my notes directory: -#+BEGIN_SRC emacs-lisp - (defun org-directory (&optional path) - "Returns the directory for my org notes, appends PATH if given" - (f-join (expand-file-name "~/org") - (s-chop-prefix (f-path-separator) (or path "")))) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (use-package org - :straight org-plus-contrib - :commands (org-element-map - org-agenda - org-capture) - :mode (("\\.org\\'" . org-mode)) - :init - (jdormit/define-prefix "o" "org") - (leader-def-key "oa" 'org-agenda) - (leader-def-key "oc" 'org-capture) - :config - ;; Disable expensive hooks when building agenda buffer - (advice-add 'org-get-agenda-file-buffer :around - (lambda (oldfn &rest args) - (let ((find-file-hook '()) - (org-mode-hook '()) - (after-change-major-mode-hook '())) - (apply oldfn args)))) - (defun agenda-files (&optional file) - (let ((agenda-dir (org-directory))) - (if file - (concat (file-name-as-directory agenda-dir) file) - agenda-dir))) - (setq org-src-fontify-natively t - org-ellipsis " ▼" - org-directory (org-directory) - org-link-elisp-confirm-function 'y-or-n-p - org-startup-with-inline-images t - org-return-follows-link t - org-log-done 'time - org-file-apps '(("log" . emacs) - (auto-mode . emacs) - (directory . emacs) - ("\\.pdf\\'" . emacs) - ("\\.mm\\'" . default) - ("\\.x?html?\\'" . default)) - org-agenda-files (list (agenda-files)) - org-capture-templates `(("L" "Lola task" entry - (file+headline ,(agenda-files "todo.org") "Lola") - "* TODO %i%?") - ("p" "Personal task" entry - (file+headline ,(agenda-files "todo.org") "Personal") - "* TODO %i%?") - ("n" "Note" entry - (file ,(agenda-files "notes.org")) - "* %^{Description}\n%i%?") - ("l" "Log" entry - (file ,(agenda-files "log.org")) - "* %<%Y-%m-%d %H:%M:%S>%?")) - org-refile-use-outline-path 'file - org-refile-targets `((org-agenda-files :level . 0) - (,(agenda-files "notes.org") :level . 1) - (,(agenda-files "todo.org") :level . 1)) - org-todo-keywords '((sequence - "TODO(t)" - "IN PROGRESS(i)" - "BLOCKED(b)" - "|" - "DONE(d)" - "CANCELLED(c)")) - org-agenda-todo-ignore-scheduled 'future - org-agenda-tags-todo-honor-ignore-options t - org-agenda-span 'day - org-agenda-custom-commands - '(("L" "Lola" ((tags-todo "@lola"))) - ("t" "TODOs" - ((agenda) - (alltodo))))) - (defun setup-org-mode () - (require 'org-attach) - (org-display-inline-images nil t) - (org-redisplay-inline-images) - (auto-fill-mode)) - (add-hook 'org-mode-hook #'setup-org-mode) - :general - (normal org-mode-map - "T" #'org-insert-todo-heading - "K" #'org-move-subtree-up - "J" #'org-move-subtree-down - "" #'org-return - "TAB" #'org-cycle - "SPC" leader-map - "gn" #'org-next-link - "gp" #'org-previous-link) - (org-mode-map "C-c e" #'org-preview-latex-fragment) - (org-mode-map "C-c C-l" #'org-insert-link) - ("C-c l" #'org-store-link)) -#+END_SRC - -** Evil-Org -Set up evil keybindings for Org mode: -#+BEGIN_SRC emacs-lisp - (use-package evil-org - :after (evil org) - :hook ((org-mode . evil-org-mode) - (org-agenda-mode . evil-org-mode)) - :config - (add-hook 'evil-org-mode-hook - (lambda () - (evil-org-set-key-theme - '(textobjects - insert - navigation - additional - shift - todo)) - (general-def 'insert org-mode-map [backspace] 'org-delete-backward-char))) - (require 'evil-org-agenda) - (evil-org-agenda-set-keys) - (general-def 'motion org-agenda-mode-map "SPC" leader-map) - (general-def 'motion org-agenda-mode-map "gs" 'org-save-all-org-buffers) - (general-def '(normal motion) evil-org-mode-map - "C-S-j" nil - "C-S-k" nil - "C-S-h" nil - "C-S-l" nil)) -#+END_SRC - -** Org-mode hydra -A helpful agenda-mode hydra: -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'org-agenda - (defhydra hydra-org-agenda (:pre (setq which-key-inhibit t) - :post (setq which-key-inhibit nil) - :hint none) - " - Org agenda (_q_uit) - - ^Clock^ ^Visit entry^ ^Date^ ^Other^ - ^-----^---- ^-----------^------------ ^----^----------- ^-----^--------- - _ci_ in _SPC_ in other window _ds_ schedule _gr_ reload - _co_ out _TAB_ & go to location _dd_ set deadline _._ go to today - _cq_ cancel _RET_ & del other windows _dt_ timestamp _gd_ go to date - _cj_ jump _o_ link _+_ do later ^^ - ^^ ^^ _-_ do earlier ^^ - ^^ ^^ ^^ ^^ - ^View^ ^Filter^ ^Headline^ ^Toggle mode^ - ^----^-------- ^------^--------------- ^--------^------- ^-----------^---- - _vd_ day _ft_ by tag _ht_ set status _tf_ follow - _vw_ week _fr_ refine by tag _hk_ kill _tl_ log - _vt_ fortnight _fc_ by category _hr_ refile _ta_ archive trees - _vm_ month _fh_ by top headline _hA_ archive _tA_ archive files - _vy_ year _fx_ by regexp _h:_ set tags _tr_ clock report - _vn_ next span _fd_ delete all filters _hp_ set priority _td_ diaries - _vp_ prev span ^^ ^^ ^^ - _vr_ reset ^^ ^^ ^^ - ^^ ^^ ^^ ^^ - " - ;; Entry - ("hA" org-agenda-archive-default) - ("hk" org-agenda-kill) - ("hp" org-agenda-priority) - ("hr" org-agenda-refile) - ("h:" org-agenda-set-tags) - ("ht" org-agenda-todo) - ;; Visit entry - ("o" link-hint-open-link :exit t) - ("" org-agenda-goto :exit t) - ("TAB" org-agenda-goto :exit t) - ("SPC" org-agenda-show-and-scroll-up) - ("RET" org-agenda-switch-to :exit t) - ;; Date - ("dt" org-agenda-date-prompt) - ("dd" org-agenda-deadline) - ("+" org-agenda-do-date-later) - ("-" org-agenda-do-date-earlier) - ("ds" org-agenda-schedule) - ;; View - ("vd" org-agenda-day-view) - ("vw" org-agenda-week-view) - ("vt" org-agenda-fortnight-view) - ("vm" org-agenda-month-view) - ("vy" org-agenda-year-view) - ("vn" org-agenda-later) - ("vp" org-agenda-earlier) - ("vr" org-agenda-reset-view) - ;; Toggle mode - ("ta" org-agenda-archives-mode) - ("tA" (org-agenda-archives-mode 'files)) - ("tr" org-agenda-clockreport-mode) - ("tf" org-agenda-follow-mode) - ("tl" org-agenda-log-mode) - ("td" org-agenda-toggle-diary) - ;; Filter - ("fc" org-agenda-filter-by-category) - ("fx" org-agenda-filter-by-regexp) - ("ft" org-agenda-filter-by-tag) - ("fr" org-agenda-filter-by-tag-refine) - ("fh" org-agenda-filter-by-top-headline) - ("fd" org-agenda-filter-remove-all) - ;; Clock - ("cq" org-agenda-clock-cancel) - ("cj" org-agenda-clock-goto :exit t) - ("ci" org-agenda-clock-in :exit t) - ("co" org-agenda-clock-out) - ;; Other - ("q" nil :exit t) - ("gd" org-agenda-goto-date) - ("." org-agenda-goto-today) - ("gr" org-agenda-redo)) - (general-def '(normal visual motion insert emacs) org-agenda-mode-map "." 'hydra-org-agenda/body)) -#+END_SRC - -** Exporting -*** HTML -Export to HTML: -#+BEGIN_SRC emacs-lisp - (use-package htmlize - :commands htmlize-buffer) -#+END_SRC - -Don't put section numbers in front of headers: -#+BEGIN_SRC emacs-lisp - (setq org-export-with-section-numbers nil) -#+END_SRC - -Disable the preamble and postamble: -#+BEGIN_SRC emacs-lisp - (setq org-html-preamble nil - org-html-postamble nil) -#+END_SRC - -Redefine org-html-src-block to wrap code blocks in
 and language class for use by highlight.js:
-#+BEGIN_SRC emacs-lisp
-  (defun org-html-src-block (src-block _contents info)
-    "Transcode a SRC-BLOCK element from Org to HTML.
-  CONTENTS holds the contents of the item.  INFO is a plist holding
-  contextual information."
-    (if (org-export-read-attribute :attr_html src-block :textarea)
-	(org-html--textarea-block src-block)
-      (let* ((lang (org-element-property :language src-block))
-	     (code (org-html-format-code src-block info))
-	     (label (let ((lbl (and (org-element-property :name src-block)
-				    (org-export-get-reference src-block info))))
-		      (if lbl (format " id=\"%s\"" lbl) "")))
-	     (klipsify  (and  (plist-get info :html-klipsify-src)
-			      (member lang '("javascript" "js"
-					     "ruby" "scheme" "clojure" "php" "html")))))
-	(if (not lang) (format "
\n%s
" label code) - (format "
\n%s%s\n
" - ;; Build caption. - (let ((caption (org-export-get-caption src-block))) - (if (not caption) "" - (let ((listing-number - (format - "%s " - (format - (org-html--translate "Listing %d:" info) - (org-export-get-ordinal - src-block info nil #'org-html--has-caption-p))))) - (format "" - listing-number - (org-trim (org-export-data caption info)))))) - ;; Contents. - (if klipsify - (format "
%s
" - lang - label - (if (string= lang "html") - " data-editor-type=\"html\"" - "") - code) - (format "
%s
" - lang lang label code))))))) -#+END_SRC - -*** Github-flavored markdown -#+BEGIN_SRC emacs-lisp - (use-package ox-gfm - :after (org) - :hook (org-mode . (lambda () (require 'ox-gfm)))) -#+END_SRC - -*** Jira -#+BEGIN_SRC emacs-lisp - (use-package ox-jira - :after (org) - :straight (:host github :repo "stig/ox-jira.el" :branch "trunk") - :hook (org-mode . (lambda () (require 'ox-jira)))) -#+END_SRC - -** org-babel -Literate programming! -#+BEGIN_SRC emacs-lisp - (add-hook 'org-mode-hook - (lambda () - (org-babel-do-load-languages - 'org-babel-load-languages - '((emacs-lisp . t) - (python . t) - (shell . t) - (clojure . t) - (lisp . t) - (scheme . t) - (java . t) - (js . t) - (dot . t) - (ditaa . t) - (ledger . t) - (sql . t) - (jq . t) - (restclient . t) - (plantuml . t))))) -#+END_SRC - -Get rid of the confirmation prompt: -#+BEGIN_SRC emacs-lisp - (setq org-confirm-babel-evaluate nil) -#+END_SRC - -Display inline images after executing a source block: -#+BEGIN_SRC emacs-lisp - (add-hook 'org-babel-after-execute-hook - (lambda () - (org-display-inline-images nil t) - (org-redisplay-inline-images))) -#+END_SRC - -Enable async source block execution. Note: this execute the contents of the source block in a separate Emacs process, so blocks that rely on anything defined in init.org or the current Emacs process won't work as expected. -#+BEGIN_SRC emacs-lisp - (use-package ob-async - :straight (ob-async :host github :repo "astahlman/ob-async") - :defer t - :hook (org-mode . (lambda () (require 'ob-async)))) -#+END_SRC - -Filter out the "u" from unicode results in org tabels returned from Python source blocks: -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'ob-python - (defun org-babel-python-table-or-string (results) - "Convert RESULTS into an appropriate elisp value. - If the results look like a list or tuple, then convert them into an - Emacs-lisp table, otherwise return the results as a string." - (let ((res (org-babel-script-escape results))) - (if (listp res) - (mapcar (lambda (el) - (cond - ((eq el 'None) org-babel-python-None-to) - ((listp el) (-filter (lambda (m) (not (eq m 'u))) el)) - (t el))) - res) - res)))) -#+END_SRC - -** Images -#+BEGIN_SRC emacs-lisp - (setq org-image-actual-width nil) -#+END_SRC - -** org-scratch -It's very useful to open a new org buffer for a quick org-babel exploration. -#+BEGIN_SRC emacs-lisp - (defun org-scratch (&optional make-new) - "Switches to an org-mode buffer not associated with any file. - If called with a prefix argument, always creates a new buffer; - otherwise, switches to the existing *org-scratch* buffer if it exists." - (interactive "P") - (let ((org-scratch-buffer-name - (generate-new-buffer-name - "*org-scratch*" - (unless make-new "*org-scratch*")))) - (switch-to-buffer org-scratch-buffer-name) - (org-mode))) - - (leader-def-key "os" #'org-scratch) -#+END_SRC - -** org-gcal -Integrate Google calendar with org-mode: -#+BEGIN_SRC emacs-lisp - (defun get-calendar-file (name) - (org-directory name)) - - (defun org-gcal-sync-advice (oldfn &rest args) - (deferred:nextc (apply oldfn args) - (lambda (_) - (dolist (entry org-gcal-fetch-file-alist) - (let ((file (cdr entry))) - (with-current-buffer (find-file-noselect file) - (save-buffer))))))) - - (use-package org-gcal - :commands (org-gcal-sync - org-gcal-fetch - org-gcal-post-at-point - org-gcal-delete-at-point - org-gcal-request-token) - :config - (advice-add 'org-gcal-sync :around #'org-gcal-sync-advice) - (setq org-gcal-client-id (password-store-get "lola-org-gcal-client-id") - org-gcal-client-secret (password-store-get "lola-org-gcal-client-secret") - org-gcal-fetch-file-alist `(("jeremydormitzer@lola.com" . ,(get-calendar-file "lola-gcal.org")) - ("jeremy.dormitzer@gmail.com" . ,(get-calendar-file "personal-gcal.org")) - ("lut2o2moohg6qkdsto1qfq7th4@group.calendar.google.com" . ,(get-calendar-file "j-n-gcal.org"))) - org-gcal-notify-p nil)) - - (defun org-agenda-redo-and-fetch-gcal (&optional all) - (interactive "P") - (let ((cb (if all #'org-agenda-redo-all #'org-agenda-redo))) - (deferred:nextc (org-gcal-fetch) cb))) - - (with-eval-after-load 'org-agenda - (general-def '(normal motion) org-agenda-mode-map "gR" #'org-agenda-redo-and-fetch-gcal)) -#+END_SRC - -** Utilities -A function to get the TITLE property of the current org buffer: -#+BEGIN_SRC emacs-lisp - (defun org-get-title (&optional contents) - (let ((raw (or contents - (buffer-substring (point-min) (point-max))))) - (with-temp-buffer - (insert raw) - (car - (org-element-map - (org-element-parse-buffer) - 'keyword - (lambda (el) - (when (string-match-p "TITLE" - (org-element-property :key el)) - (org-element-property :value el)))))))) -#+END_SRC - -** org-present -An ultra-minimalist presentation mode for Org: -#+BEGIN_SRC emacs-lisp - (use-package org-present - :commands (org-present) - :config - (defun org-present-on () - (org-present-big) - (org-display-inline-images) - (org-present-hide-cursor) - (display-line-numbers-mode -1) - (org-present-read-only)) - (defun org-present-off () - (org-present-small) - (org-present-show-cursor) - (unless org-startup-with-inline-images - (org-remove-inline-images)) - (display-line-numbers-mode) - (org-present-read-write)) - (add-hook 'org-present-mode-hook #'org-present-on) - (add-hook 'org-present-mode-quit-hook #'org-present-off) - ;; Redefine org-present to call org-present-narrow after running hooks - (defun org-present () - "init." - (interactive) - (setq org-present-mode t) - (org-present-add-overlays) - (run-hooks 'org-present-mode-hook) - (org-present-narrow) - (org-present-run-after-navigate-functions)) - :init - (general-def '(normal visual motion emacs) org-present-mode-keymap - "" #'org-present-prev - "" #'org-present-next - "C-k" #'org-present-prev - "C-j" #'org-present-next - "q" #'org-present-quit)) -#+END_SRC - -** org-cliplink -Intelligently inserts an org-mode link from the clipboard. -#+BEGIN_SRC emacs-lisp - (use-package org-cliplink - :after (org) - :commands (org-cliplink - org-cliplink-clipboard-content) - :general - (org-mode-map "C-c C-S-L" #'org-cliplink)) -#+END_SRC - -** org-board -[[https://github.com/scallywag/org-board][Org-board]] is a bookmarking/archiving system built on Org mode: -#+BEGIN_SRC emacs-lisp - (use-package org-board - :after (org) - :config - - ;; Org-capture setup - - (defvar org-capture-bookmark-last-url nil) - (defvar org-capture-bookmark-last-title nil) - - (defun org-capture-bookmark-get-url () - (let* ((clip (org-cliplink-clipboard-content)) - (parsed (url-generic-parse-url clip))) - (if (url-type parsed) - clip - (read-string "Bookmark URL: ")))) - - (defun org-capture-bookmark-get-title (url) - (or (org-cliplink-retrieve-title-synchronously url) - (read-string "Bookmark title: "))) - - (defun bookmark-file (title) - (org-directory (format "%s.org" (org-roam--get-new-id title)))) - - (defun org-capture-bookmark-file () - (let* ((url (org-capture-bookmark-get-url)) - (title (org-capture-bookmark-get-title url))) - (setq org-capture-bookmark-last-url url) - (setq org-capture-bookmark-last-title title) - (bookmark-file title))) - - (defun org-capture-bookmark-link () - (format "[[%s][%s]]" - org-capture-bookmark-last-url - org-capture-bookmark-last-title)) - - (defun org-capture-bookmark-title () - org-capture-bookmark-last-title) - - (defun save-bookmark (url) - (save-excursion - (goto-char (point-min)) - (when (search-forward "* Bookmark" nil t) - (org-board-new url) - (wallabag-add-entry url - (cl-function - (lambda (&key data &allow-other-keys) - (let ((entry-url (format "%s/view/%s" - wallabag-base-url - (alist-get 'id data)))) - (message "Added bookmark to Wallabag: %s" entry-url)))))))) - - (defun org-capture-bookmark-after-finalize () - "Runs `org-board-new' on the captured entry. - Also saves to Wallabag." - (let ((success (not org-note-abort)) - (key (plist-get org-capture-plist :key)) - (desc (plist-get org-capture-plist :description))) - (when (and success - (equal key "b") - (equal desc "Bookmark") - org-capture-bookmark-last-url) - (save-bookmark org-capture-bookmark-last-url) - (setq org-capture-bookmark-last-url nil) - (setq org-capture-bookmark-last-title nil)))) - - (add-hook 'org-capture-prepare-finalize-hook - #'org-capture-bookmark-after-finalize) - - (add-to-list 'org-capture-templates - '("b" "Bookmark" plain - (file org-capture-bookmark-file) - "#+TITLE: %(org-capture-bookmark-title)\n\n- tags :: [[file:deft/bookmarks.org][Bookmarks]]\n- source :: %(org-capture-bookmark-link)\n%?\n* Bookmark")) - - ;; Org-protocol setup - (defun make-org-protocol-bookmark (url title) - (with-temp-buffer - (let ((filename (bookmark-file title))) - (save-excursion - (insert (concat (format "#+TITLE: %s\n\n" title) - "- tags :: [[file:deft/bookmarks.org][Bookmarks]]\n" - (format "- source :: [[%s][%s]]\n\n" url title) - "* Bookmark")) - (write-file filename) - (save-bookmark url) - (save-buffer))))) - - (defun bookmark-via-org-protocol (url) - (org-cliplink-retrieve-title (url-unhex-string url) #'make-org-protocol-bookmark)) - - (with-eval-after-load 'org-protocol - (add-to-list 'org-protocol-protocol-alist - '("Bookmark" - :protocol "bookmark" - :function bookmark-via-org-protocol - :kill-client t))) - - (add-to-list 'org-board-wget-switches "--recursive") - (add-to-list 'org-board-wget-switches "--level=1") - (add-to-list 'org-board-wget-switches "--span-hosts") - ;; Use w3m instead of eww to open org-board archived links - (advice-add 'org-board-open-with :around - (lambda (oldfn filename-string arg &rest args) - (cond - ((not (file-exists-p filename-string)) 1) - ((and filename-string - (or (and arg (eq org-board-default-browser 'system)) - (and (not arg) (eq org-board-default-browser 'eww)))) - (let ((filename (concat "file://" - (s-chop-prefix "file://" - filename-string)))) - (w3m filename t) - 0)) - (:else (apply oldfn filename-string arg args))))) - :general - (org-mode-map "C-c b" org-board-keymap)) -#+END_SRC - -** org-rifle -Quickly find stuff in Org files: -#+BEGIN_SRC emacs-lisp - (use-package helm-org-rifle - :commands (helm-org-rifle - helm-org-rifle-agenda-files - helm-org-rifle-current-buffer - helm-org-rifle-directories - helm-org-rifle-files - helm-org-rifle-org-directory - helm-org-rifle-occur - helm-org-rifle-occur-agenda-files - helm-org-rifle-occur-current-buffer - helm-org-rifle-occur-directories - helm-org-rifle-occur-files - helm-org-rifle-occur-org-directory) - :init - (defvar helm-org-rifle-commands-map (make-sparse-keymap)) - (general-def helm-org-rifle-commands-map - "r" #'helm-org-rifle - "a" #'helm-org-rifle-agenda-files - "b" #'helm-org-rifle-current-buffer - "d" #'helm-org-rifle-directories - "f" #'helm-org-rifle-files - "o" #'helm-org-rifle-org-directory - "R" #'helm-org-rifle-occur - "A" #'helm-org-rifle-occur-agenda-files - "B" #'helm-org-rifle-occur-current-buffer - "D" #'helm-org-rifle-occur-directories - "F" #'helm-org-rifle-occur-files - "O" #'helm-org-rifle-occur-org-directory) - (leader-def-key "or" helm-org-rifle-commands-map) - (jdormit/define-prefix "or" "org-rifle") - :config - (defun around-helm-org-rifle (oldfn &rest args) - (if (and (boundp 'centaur-tabs-mode) centaur-tabs-mode) - (progn - (centaur-tabs-mode -1) - (apply oldfn args) - (centaur-tabs-mode 1)) - (apply oldfn args))) - (advice-add 'helm-org-rifle :around #'around-helm-org-rifle)) -#+END_SRC - -** Org Noter -[[https://github.com/weirdNox/org-noter][Org Noter]] lets me take org-mode notes on PDFs, epubs, and DocView files: -#+BEGIN_SRC emacs-lisp - (use-package org-noter - :commands org-noter - :general - (normal org-noter-doc-mode-map - "i" #'org-noter-insert-note - "q" #'org-noter-kill-session - "C-M-n" #'org-noter-sync-next-note - "C-M-p" #'org-noter-sync-prev-note - "M-." #'org-noter-sync-current-page-or-chapter - "M-i" #'org-noter-insert-precise-note - "M-n" #'org-noter-sync-next-page-or-chapter - "M-p" #'org-noter-sync-prev-page-or-chapter - "C-M-." #'org-noter-sync-current-note)) -#+END_SRC - -** Org Roam -[[https://org-roam.readthedocs.io/en/develop/][Org-roam]] is another backlink package for org-mode: -#+BEGIN_SRC emacs-lisp - (use-package org-roam - :straight (:host github :repo "jethrokuan/org-roam") - :commands - (org-roam - org-roam-today - org-roam-find-file - org-roam-insert - org-roam-show-graph - org-roam--get-new-id) - :custom - (org-roam-directory (org-directory)) - :init - (defvar org-roam-map (make-sparse-keymap)) - (jdormit/define-prefix "on" "org-roam") - (which-key-add-key-based-replacements "C-c n" "org-roam") - (which-key-add-major-mode-key-based-replacements - 'org-mode "gn" "org-roam") - (with-eval-after-load 'org - (org-roam-mode)) - :config - (add-hook 'org-roam-backlinks-mode-hook #'olivetti-mode) - :general - (leader-map "fo" #'org-roam-find-file - "of" #'org-roam-find-file - "on" org-roam-map) - (org-roam-map "l" #'org-roam - "t" #'org-roam-today - "f" #'org-roam-find-file - "i" #'org-roam-insert - "g" #'org-roam-show-graph) - (normal org-mode-map - "gr" org-roam-map) - (normal org-roam-backlinks-mode-map - "" #'org-open-at-point - "q" #'quit-window) - ("C-c n" org-roam-map)) -#+END_SRC - -** org-journal -[[https://github.com/bastibe/org-journal][org-journal]] is a package that provides some convenience functions -around keeping a daily Org-mode journal. I also set it up so it plays -nice with Org-roam: -#+BEGIN_SRC emacs-lisp - (use-package org-journal - :commands (org-journal-today - org-journal-new-entry) - :init - (defun org-journal-file-header-func (time) - (format "#+TITLE: %s" - (format-time-string "%Y-%m-%d" time))) - (defun org-journal-today () - (interactive) - (org-journal-new-entry t)) - (defun org-journal-capture-func () - (org-journal-new-entry t) - (goto-char (point-min)) - ;; Account for the #+TITLE - (forward-line)) - (jdormit/define-prefix "oj" "org-journal") - (leader-def-key "ojn" #'org-journal-new-entry) - (leader-def-key "ojt" #'org-journal-today) - :config - (add-to-list 'org-capture-templates - '("j" "Journal entry" entry (function org-journal-capture-func) - "* %(format-time-string org-journal-time-format)\n%?")) - :custom - (org-journal-file-type 'daily) - (org-journal-dir (org-directory)) - (org-journal-file-format "%Y-%m-%d.org") - (org-journal-file-header 'org-journal-file-header-func) - (org-journal-carryover-items "") - :general - (org-roam-map "t" 'org-journal-today)) -#+END_SRC - -** org-super-agenda -#+BEGIN_SRC emacs-lisp - (use-package org-super-agenda - :after (org) - :init - (setq org-super-agenda-groups - '((:name "In progress" - :todo "IN PROGRESS") - (:name "Lola" - :tag "@lola") - (:name "unifyDB" - :tag "@unifydb") - (:name "Personal" - :tag "@personal"))) - (org-super-agenda-mode) - :config - (setq org-super-agenda-header-map (make-sparse-keymap))) -#+END_SRC - -** Org-Jira -Jira in Emacs: -#+BEGIN_SRC emacs-lisp - (use-package org-jira - :after (org) - :init - (setq jiralib-url "https://lola.atlassian.net" - org-jira-working-dir (org-directory "jira") - org-jira-jira-status-to-org-keyword-alist '(("To Do" . "TODO") - ("Blocked" . "BLOCKED") - ("In Progress" . "IN PROGRESS") - ("Code Review" . "IN PROGRESS") - ("Awaiting Release" . "IN PROGRESS") - ("Done" . "DONE") - ("Won't Fix" . "CANCELLED"))) - (add-to-list 'org-agenda-files org-jira-working-dir) - (add-to-list 'org-super-agenda-groups - `(:name "Jira" :file-path ,org-jira-working-dir) - t)) -#+END_SRC - -* Doom themes -#+BEGIN_SRC emacs-lisp - (use-package doom-themes) - - (use-package doom-modeline) - (doom-modeline-mode 1) -#+END_SRC - -* Ewal theme -#+BEGIN_SRC emacs-lisp - (use-package doom-ewal-themes - :straight (doom-ewal-themes - :host github - :repo "jdormit/doom-ewal-themes" - :files ("themes" :defaults))) -#+END_SRC - -* Customization File -I don't want anything to write to my init.el, so save customizations in a separate file: -#+BEGIN_SRC emacs-lisp - (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) - (load custom-file t) -#+END_SRC - -* Path -`exec-path-from-shell` uses Bash to set MANPATH, PATH, and exec-path from those defined in the user's shell config. This won't work on Windows. -#+BEGIN_SRC emacs-lisp - (use-package exec-path-from-shell - :if (memq window-system '(mac ns x)) - :config - (setq exec-path-from-shell-variables '("PATH" "MANPATH" "LEDGER_FILE" "LOLA_HOME" - "MODELS_HOME" "LOLA_TRAVEL_SERVICE_HOME" "WORKON_HOME" - "PIPENV_VERBOSITY" "PIPENV_DONT_LOAD_ENV" - "PIPENV_MAX_DEPTH" "PYENV_ROOT" "KOPS_STATE_STORE" - "PLAID_CLIENT_ID" "PLAID_SECRET" "PLAID_ENVIRONMENT") - exec-path-from-shell-check-startup-files nil) - (exec-path-from-shell-initialize)) -#+END_SRC - -* Autocompletion -There seems to be [[https://github.com/company-mode/company-mode/issues/68][some contention]] about whether autocomplete or company are better autocomplete packages. I'm going with company for now because the maintainer seems nicer... -#+BEGIN_SRC emacs-lisp - (use-package company - :commands (company-complete - company-mode) - :hook ((prog-mode . company-mode)) - :config - (setq company-idle-delay 0.3)) - - (general-def "C-M-i" #'company-complete) - (general-def "M-" #'company-complete) -#+END_SRC - -* Multiple cursors -#+BEGIN_SRC emacs-lisp - (use-package evil-mc - :defer 0 - :config - (global-evil-mc-mode) - (general-def '(normal visual) - "gs" evil-mc-cursors-map - "M-n" #'evil-mc-make-and-goto-next-cursor - "M-p" #'evil-mc-make-and-goto-prev-cursor - "C-n" #'evil-mc-make-and-goto-next-match - "C-t" #'evil-mc-skip-and-goto-next-match - "C-p" #'evil-mc-make-and-goto-prev-match)) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (use-package evil-multiedit - :defer 0 - :config - (evil-multiedit-default-keybinds)) -#+END_SRC - -* Transient -A framework for creating Magit-style popups: -#+BEGIN_SRC emacs-lisp - (use-package transient - :commands (define-transient-command)) -#+END_SRC - -* Magit -Magit is objectively the best Git interface. -#+BEGIN_SRC emacs-lisp - (use-package magit - :commands (magit-status - magit-blame - magit-find-file - magit-name-local-branch)) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "g" "git") - (leader-def-key - "gs" #'magit-status - "gg" #'magit-file-dispatch - "gd" #'magit-dispatch - "gf" #'magit-find-file) -#+END_SRC - -** Forge -[[https://github.com/magit/forge][Forge]] is an extension for Magit that lets it interact with code forges (e.g. GitHub). -#+BEGIN_SRC emacs-lisp - (use-package forge - :after (magit) - :config - (add-to-list 'forge-alist '("git.jeremydormitzer.com" - "git.jeremydormitzer.com/api/v1" - "git.jeremydormitzer.com" - forge-gitea-repository)) - (with-eval-after-load 'evil-magit - (general-def '(normal motion) magit-mode-map - "yu" #'forge-copy-url-at-point-as-kill)) - :general - ((normal motion visual) forge-topic-list-mode-map - "y" #'forge-copy-url-at-point-as-kill - "q" #'quit-window) - :custom - (forge-owned-accounts '((jdormit . (remote-name "jdormit"))))) -#+END_SRC - -** evil-magit -Evil keybindings for magit! -#+BEGIN_SRC emacs-lisp - (use-package evil-magit - :after (evil magit) - :config - (with-eval-after-load 'magit - (require 'evil-magit)) - :general - ('normal magit-mode-map "SPC" leader-map)) -#+END_SRC - -** Transient -#+BEGIN_SRC emacs-lisp - (setq transient-default-level 7) -#+END_SRC - -* git-link -Open files in Git forges (GitHub, GitLab, etc.): -#+BEGIN_SRC emacs-lisp - (use-package git-link - :commands (git-link) - :init - (defun git-link-copy () - (interactive) - (let ((git-link-open-in-browser nil)) - (call-interactively 'git-link))) - (leader-def-key "gl" #'git-link) - (leader-def-key "gy" #'git-link-copy) - :custom - (git-link-open-in-browser t) - (git-link-remote-alist '(("git.sr.ht" git-link-sourcehut) - ("github" git-link-github) - ("bitbucket" git-link-bitbucket) - ("gitorious" git-link-gitorious) - ("gitlab" git-link-gitlab) - ("visualstudio\\|azure" git-link-azure) - ("git.jeremydormitzer.com" git-link-bitbucket)))) -#+END_SRC - -* with-editor -A utility from the author of Magit to run shell commands using the current Emacs instance as $EDITOR. - -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'with-editor - (shell-command-with-editor-mode) - (add-hook 'shell-mode-hook #'with-editor-export-editor) - (add-hook 'term-exec-hook #'with-editor-export-editor) - (add-hook 'eshell-mode-hook #'with-editor-export-editor)) -#+END_SRC - -* Password Store -Interfacing with Pass, the "standard Unix password manager". This should also be loaded before `exec-path-from-shell`. -#+BEGIN_SRC emacs-lisp - (defun password-store-synchronize () - (interactive) - (with-editor-async-shell-command "pass git pull && pass git push")) - - (use-package password-store - :defer t - :if (executable-find "pass") - :config - (setq password-store-password-length 20) - :init - (leader-def-key "P" 'password-store-copy) - (epa-file-enable)) - - (use-package pass - :if (executable-find "pass") - :commands pass - :general - (normal pass-mode-map "S" #'password-store-synchronize)) - - (leader-def-key "ap" #'pass) - - (setq auth-sources '("~/.authinfo" password-store)) -#+END_SRC - -* Init File -A function to reload my init file. It reloads the major mode after the init file is loaded to rebind keymappings. -#+BEGIN_SRC emacs-lisp - (defun reload-init-file () - (interactive) - (load-file "~/.emacs.d/init.el") - (funcall major-mode)) -#+END_SRC - -And another one to edit it: -#+BEGIN_SRC emacs-lisp - (defun find-init-file () - (interactive) - (find-file "~/.emacs.d/init.org")) -#+END_SRC - -* Keybindings -These are general keybindings; those specific to certain packages are in the sections for those packages. - - -In some modes I want vanilla Emacs bindings: -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'evil - (add-to-list 'evil-emacs-state-modes 'benchmark-init/tabulated-mode) - (add-to-list 'evil-emacs-state-modes 'benchmark-init/tree-mode) - (add-to-list 'evil-emacs-state-modes 'cider-stacktrace-mode) - (add-to-list 'evil-emacs-state-modes 'geiser-debug-mode) - (add-to-list 'evil-emacs-state-modes 'undo-tree-visualizer-mode) - (add-to-list 'evil-emacs-state-modes 'makey-key-mode) - (add-to-list 'evil-emacs-state-modes 'term-mode)) -#+END_SRC - -** Visual line navigation -#+BEGIN_SRC emacs-lisp - (general-def 'motion "j" #'evil-next-visual-line) - (general-def 'motion "k" #'evil-previous-visual-line) - (general-def 'motion "j" #'evil-next-visual-line) - (general-def 'motion "k" #'evil-previous-visual-line) -#+END_SRC - -** M-x -#+BEGIN_SRC emacs-lisp - (leader-def-key "SPC" 'execute-extended-command) -#+END_SRC - -** Eval-ing -#+BEGIN_SRC emacs-lisp - (leader-def-key ":" #'eval-expression) -#+END_SRC - -** Init file commands -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "." "dotfile") - (leader-def-key ".r" 'reload-init-file) - (leader-def-key ".f" 'find-init-file) -#+END_SRC - -** Commands about files -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "f" "files") - (leader-def-key "ff" 'find-file) - (leader-def-key "fd" 'dired) - (leader-def-key "fs" 'sudo-find-file) - (leader-def-key "ft" 'auto-revert-tail-mode) - (leader-def-key "fp" 'find-file-at-point) - (general-def '(normal motion visual) "gf" 'find-file-at-point) -#+END_SRC - -** Window commands -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "w" "window") - (leader-def-key "w/" 'split-window-right) - (leader-def-key "w-" 'split-window-below) - (leader-def-key "wm" 'delete-other-windows) - (leader-def-key "wd" 'delete-window) - (leader-def-key "ws" 'window-swap-states) -#+END_SRC - -** Buffer commands -A function to switch to previous buffer from [[http://emacsredux.com/blog/2013/04/28/switch-to-previous-buffer/][this blog post]]: -#+BEGIN_SRC emacs-lisp - (defun switch-to-previous-buffer () - "Switch to previously open buffer. - Repeated invocations toggle between the two most recently open buffers." - (interactive) - (switch-to-buffer (other-buffer (current-buffer) 1))) - - (leader-def-key "TAB" 'switch-to-previous-buffer) -#+END_SRC - -A function to kill all buffers except the current one from [[https://www.emacswiki.org/emacs/KillingBuffers#toc2][EmacsWiki]]: -#+BEGIN_SRC emacs-lisp - (defun kill-other-buffers () - "Kill all other buffers." - (interactive) - (mapc 'kill-buffer (delq (current-buffer) (buffer-list)))) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "b" "buffer") - (leader-def-key "bb" #'switch-to-buffer) - (leader-def-key "bn" #'next-buffer) - (leader-def-key "bp" #'previous-buffer) - (leader-def-key "bd" #'kill-buffer) - (leader-def-key "bm" #'kill-other-buffers) - (leader-def-key "br" #'rename-buffer) -#+END_SRC - -** Frame commands -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "F" "frame") - (leader-def-key "Fn" #'make-frame-command) - (leader-def-key "Fo" #'other-frame) - (leader-def-key "Fm" #'delete-other-frames) - (leader-def-key "Fd" #'delete-frame) -#+END_SRC - -** Running shell commands -#+BEGIN_SRC emacs-lisp - (leader-def-key "!" 'shell-command) - (leader-def-key "|" 'shell-command-on-region) - (general-def 'normal shell-mode-map "q" #'bury-buffer) -#+END_SRC - -** Toggles -Like in Spacemacs, put all toggle commands behind a prefix: -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "t" "toggle") -#+END_SRC - -Toggles about line truncation: -#+BEGIN_SRC emacs-lisp - (leader-def-key "tt" 'toggle-truncate-lines) - (leader-def-key "tT" 'visual-line-mode) - (leader-def-key "tf" 'auto-fill-mode) -#+END_SRC - -Toggle lisp debugging: -#+BEGIN_SRC emacs-lisp - (leader-def-key "td" 'toggle-debug-on-error) -#+END_SRC - -** Shells/REPLs -Emacs has a shell for every mood! -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "s" "shells/REPLs") - (leader-def-key "ss" 'shell) - (leader-def-key "si" 'ielm) - (leader-def-key "se" 'eshell) - (leader-def-key "sa" 'ansi-term) -#+END_SRC - -** Applications -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "a" "applications") -#+END_SRC - -** Help Buffers -#+BEGIN_SRC emacs-lisp - (general-def 'motion help-mode-map "TAB" #'forward-button) -#+END_SRC - -** Code commands -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "c" "code") - (leader-def-key "cd" #'xref-find-definitions) - (leader-def-key "cr" #'xref-find-references) - (leader-def-key "ca" #'xref-find-apropos) - (general-def 'normal "M-." #'xref-find-definitions) -#+END_SRC - -** Process list -#+BEGIN_SRC emacs-lisp - (general-def '(normal motion visual) process-menu-mode-map - "d" #'process-menu-delete-process) -#+END_SRC - -** Registers -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "r" "registers") - (leader-def-key "r" ctl-x-r-map) -#+END_SRC - -* Evil-numbers -Handy functions to increment/decrement numbers at point: -#+BEGIN_SRC emacs-lisp - (use-package evil-numbers - :straight (:host github :repo "janpath/evil-numbers") - :general - ((normal visual motion) "g+" 'evil-numbers/inc-at-pt) - ((normal visual motion) "g-" 'evil-numbers/dec-at-pt) - ((normal visual motion) "g C-+" 'evil-numbers/inc-at-pt-incremental) - ((normal visual motion) "g C--" 'evil-numbers/dec-at-pt-incremental)) -#+END_SRC - -* Winner -Winner is a minor mode that keeps an undo/redo history of the window configuration: -#+BEGIN_SRC emacs-lisp - (winner-mode 1) - (leader-def-key "wn" #'winner-redo) - (leader-def-key "wp" #'winner-undo) -#+END_SRC - -* Buffer move -A handy package to shift buffers between open windows: -#+BEGIN_SRC emacs-lisp - (use-package buffer-move - :general - ("C-S-j" #'buf-move-down) - ("C-S-k" #'buf-move-up) - ("C-S-h" #'buf-move-left) - ("C-S-l" #'buf-move-right)) -#+END_SRC - -* Info -#+BEGIN_SRC emacs-lisp - (use-package info - :init - (defhydra hydra-info (:color blue - :hint nil) - " - Info-mode: - - ^^_]_ forward (next logical node) ^^_l_ast (←) _u_p (↑) _f_ollow reference _T_OC - ^^_[_ backward (prev logical node) ^^_r_eturn (→) _m_enu (↓) (C-u for new window) _i_ndex _d_irectory - ^^_n_ext (same level only) ^^_H_istory _g_oto (C-u for new window) _,_ next index item _c_opy node name - ^^_p_rev (same level only) _<_/_t_op _b_eginning of buffer virtual _I_ndex _C_lone buffer - regex _s_earch (_S_ case sensitive) ^^_>_ final _e_nd of buffer ^^ _a_propos - - _1_ .. _9_ Pick first .. ninth item in the node's menu. - - " - ("]" Info-forward-node) - ("[" Info-backward-node) - ("n" Info-next) - ("p" Info-prev) - ("s" Info-search) - ("S" Info-search-case-sensitively) - - ("l" Info-history-back) - ("r" Info-history-forward) - ("H" Info-history) - ("t" Info-top-node) - ("<" Info-top-node) - (">" Info-final-node) - - ("u" Info-up) - ("^" Info-up) - ("m" Info-menu) - ("g" Info-goto-node) - ("b" beginning-of-buffer) - ("e" end-of-buffer) - - ("f" Info-follow-reference) - ("i" Info-index) - ("," Info-index-next) - ("I" Info-virtual-index) - - ("T" Info-toc) - ("d" Info-directory) - ("c" Info-copy-current-node-name) - ("C" clone-buffer) - ("a" info-apropos) - - ("1" Info-nth-menu-item) - ("2" Info-nth-menu-item) - ("3" Info-nth-menu-item) - ("4" Info-nth-menu-item) - ("5" Info-nth-menu-item) - ("6" Info-nth-menu-item) - ("7" Info-nth-menu-item) - ("8" Info-nth-menu-item) - ("9" Info-nth-menu-item) - - ("?" Info-summary "Info summary") - ("h" Info-help "Info help") - ("q" Info-exit "Info exit") - ("C-g" nil "cancel" :color blue)) - :general - (Info-mode-map "C-/" 'hydra-info/body)) -#+END_SRC - -* xref -After I select an xref reference, I want the xref buffer closed: -#+BEGIN_SRC emacs-lisp - (defun xref-goto-xref-and-quit () - (interactive) - (xref-goto-xref t)) - (general-def 'normal xref--xref-buffer-mode-map "RET" - #'xref-goto-xref-and-quit :keymaps 'override) -#+END_SRC - -Don't prompt for an identifier for these xref commands: -#+BEGIN_SRC emacs-lisp - (setq xref-prompt-for-identifier - '(not xref-find-definitions - xref-find-definitions-other-window - xref-find-definitions-other-frame - xref-find-references)) -#+END_SRC - -Some keybindings: -#+BEGIN_SRC emacs-lisp - (general-def "M-r" #'xref-find-references) -#+END_SRC - -* IBuffer -#+BEGIN_SRC emacs-lisp - (use-package ibuffer - :straight (:type built-in) - :init - (defhydra hydra-ibuffer-main (:color pink :hint nil) - " - ^Navigation^ | ^Mark^ | ^Actions^ | ^View^ - -^----------^-+-^----^--------+-^-------^--------+-^----^------- - _k_: ʌ | _m_: mark | _D_: delete | _g_: refresh - _RET_: visit | _u_: unmark | _S_: save | _s_: sort - _j_: v | _*_: specific | _a_: all actions | _/_: filter - -^----------^-+-^----^--------+-^-------^--------+-^----^------- - " - ("j" ibuffer-forward-line) - ("RET" ibuffer-visit-buffer :color blue) - ("k" ibuffer-backward-line) - - ("m" ibuffer-mark-forward) - ("u" ibuffer-unmark-forward) - ("*" hydra-ibuffer-mark/body :color blue) - - ("D" ibuffer-do-delete) - ("S" ibuffer-do-save) - ("a" hydra-ibuffer-action/body :color blue) - - ("g" ibuffer-update) - ("s" hydra-ibuffer-sort/body :color blue) - ("/" hydra-ibuffer-filter/body :color blue) - - ("o" ibuffer-visit-buffer-other-window "other window" :color blue) - ("q" quit-window "quit ibuffer" :color blue) - ("." nil "toggle hydra" :color blue)) - - (defhydra hydra-ibuffer-mark (:color teal - :columns 5 - :after-exit (hydra-ibuffer-main/body)) - "Mark" - ("*" ibuffer-unmark-all "unmark all") - ("M" ibuffer-mark-by-mode "mode") - ("m" ibuffer-mark-modified-buffers "modified") - ("u" ibuffer-mark-unsaved-buffers "unsaved") - ("s" ibuffer-mark-special-buffers "special") - ("r" ibuffer-mark-read-only-buffers "read-only") - ("/" ibuffer-mark-dired-buffers "dired") - ("e" ibuffer-mark-dissociated-buffers "dissociated") - ("h" ibuffer-mark-help-buffers "help") - ("z" ibuffer-mark-compressed-file-buffers "compressed") - ("b" hydra-ibuffer-main/body "back" :color blue)) - - (defhydra hydra-ibuffer-action (:color teal - :columns 4 - :after-exit - (if (eq major-mode 'ibuffer-mode) - (hydra-ibuffer-main/body))) - "Action" - ("A" ibuffer-do-view "view") - ("E" ibuffer-do-eval "eval") - ("F" ibuffer-do-shell-command-file "shell-command-file") - ("I" ibuffer-do-query-replace-regexp "query-replace-regexp") - ("H" ibuffer-do-view-other-frame "view-other-frame") - ("N" ibuffer-do-shell-command-pipe-replace "shell-cmd-pipe-replace") - ("M" ibuffer-do-toggle-modified "toggle-modified") - ("O" ibuffer-do-occur "occur") - ("P" ibuffer-do-print "print") - ("Q" ibuffer-do-query-replace "query-replace") - ("R" ibuffer-do-rename-uniquely "rename-uniquely") - ("T" ibuffer-do-toggle-read-only "toggle-read-only") - ("U" ibuffer-do-replace-regexp "replace-regexp") - ("V" ibuffer-do-revert "revert") - ("W" ibuffer-do-view-and-eval "view-and-eval") - ("X" ibuffer-do-shell-command-pipe "shell-command-pipe") - ("b" nil "back")) - - (defhydra hydra-ibuffer-sort (:color amaranth :columns 3) - "Sort" - ("i" ibuffer-invert-sorting "invert") - ("a" ibuffer-do-sort-by-alphabetic "alphabetic") - ("v" ibuffer-do-sort-by-recency "recently used") - ("s" ibuffer-do-sort-by-size "size") - ("f" ibuffer-do-sort-by-filename/process "filename") - ("m" ibuffer-do-sort-by-major-mode "mode") - ("b" hydra-ibuffer-main/body "back" :color blue)) - - (defhydra hydra-ibuffer-filter (:color amaranth :columns 4) - "Filter" - ("m" ibuffer-filter-by-used-mode "mode") - ("M" ibuffer-filter-by-derived-mode "derived mode") - ("n" ibuffer-filter-by-name "name") - ("c" ibuffer-filter-by-content "content") - ("e" ibuffer-filter-by-predicate "predicate") - ("f" ibuffer-filter-by-filename "filename") - (">" ibuffer-filter-by-size-gt "size") - ("<" ibuffer-filter-by-size-lt "size") - ("/" ibuffer-filter-disable "disable") - ("b" hydra-ibuffer-main/body "back" :color blue)) - :general - ((normal motion visual insert emacs) ibuffer-mode-map "." 'hydra-ibuffer-main/body)) - -#+END_SRC - -* Speedbar -Speedbar is cool but having it open in a separate frame is annoying. This makes it open in a side window in the same frame: -#+BEGIN_SRC emacs-lisp - (use-package sr-speedbar - :commands (sr-speedbar-toggle - sr-speedbar-open - sr-speedbar-select-window - sr-speedbar-exist-p) - :general - (speedbar-mode-map "q" #'sr-speedbar-close)) - - (defun switch-to-speedbar () - (interactive) - (unless (sr-speedbar-exist-p) - (sr-speedbar-open)) - (sr-speedbar-select-window)) - - (leader-def-key "S" #'switch-to-speedbar) -#+END_SRC - -* Trailing whitespace -[[https://github.com/lewang/ws-butler][ws-butler]] deletes trailing whitespace on lines that you touch, but -leaves other lines alone: -#+BEGIN_SRC emacs-lisp - (use-package ws-butler - :straight (ws-butler :host github :repo "lewang/ws-butler") - :hook ((prog-mode . ws-butler-mode))) -#+END_SRC - -* Whitespace Visualation -#+BEGIN_SRC emacs-lisp - (setq whitespace-line-column 80 - whitespace-style '(face lines-tail)) - (leader-def-key "tw" #'whitespace-mode) -#+END_SRC - -* Line Numbers -Toggle line numbers: -#+BEGIN_SRC emacs-lisp - (setq display-line-numbers-type 'visual) - (leader-def-key "tn" 'display-line-numbers-mode) -#+END_SRC - -Toggle line numbering mode (normal or relative): -#+BEGIN_SRC emacs-lisp - (defun toggle-line-number-mode () - (interactive) - (when display-line-numbers - (if (eq display-line-numbers 'visual) - (progn - (setq display-line-numbers t) - (setq display-line-numbers-type t)) - (progn - (setq display-line-numbers 'visual) - (setq display-line-numbers-type 'visual))))) - - (leader-def-key "tr" #'toggle-line-number-mode) -#+END_SRC - -Display line numbers by default in code and org-mode buffers: -#+BEGIN_SRC emacs-lisp - (add-hook 'prog-mode-hook #'display-line-numbers-mode) - (add-hook 'org-mode-hook #'display-line-numbers-mode) -#+END_SRC - -* Amx -A better M-x. -#+BEGIN_SRC emacs-lisp - (use-package amx - :config - (amx-mode)) -#+END_SRC - -* Olivetti Mode -Olivetti is a minor mode for a nice writing environment. -#+BEGIN_SRC emacs-lisp - (use-package olivetti - :config - (setq-default olivetti-body-width 100) - (setq olivetti-body-width 100) - :commands olivetti-mode) - - (leader-def-key "to" 'olivetti-mode) -#+END_SRC - -* Winum -This package includes functions to switch windows by number. -#+BEGIN_SRC emacs-lisp - (defun winum-assign-0-to-dired-sidebar () - (when (equal major-mode 'dired-sidebar-mode) 10)) - - (use-package winum - :config - (winum-mode) - (add-to-list 'winum-assign-functions #'winum-assign-0-to-dired-sidebar) - (leader-def-key "0" 'winum-select-window-0-or-10) - (leader-def-key "1" 'winum-select-window-1) - (leader-def-key "2" 'winum-select-window-2) - (leader-def-key "3" 'winum-select-window-3) - (leader-def-key "4" 'winum-select-window-4) - (leader-def-key "5" 'winum-select-window-5) - (leader-def-key "6" 'winum-select-window-6) - (leader-def-key "7" 'winum-select-window-7) - (leader-def-key "8" 'winum-select-window-8) - (leader-def-key "9" 'winum-select-window-9) - :custom - (winum-scope 'frame-local)) -#+END_SRC - -I don't want which-key display "lambda" for the descriptions of these, so set a custom display function. This is [[https://github.com/syl20bnr/spacemacs/blob/master/layers/+distributions/spacemacs-bootstrap/packages.el#L312][stolen from Spacemacs]]. -#+BEGIN_SRC emacs-lisp - (push '(("\\(.*\\) 0" . "select-window-0") . ("\\1 0..9" . "window 0..9")) - which-key-replacement-alist) - (push '((nil . "select-window-[1-9]") . t) which-key-replacement-alist) -#+END_SRC - -* Backups and Autosaves -Store backups and autosaves in a centralized place. This should really be the default... -#+BEGIN_SRC emacs-lisp - (make-directory (expand-file-name "~/.emacs.d/autosaves") t) - (setq auto-save-file-name-transforms '((".*" "~/.emacs.d/autosaves" t))) - (setq backup-directory-alist '(("." . "~/.emacs.d/backups"))) -#+END_SRC - -* Smartparens/Parinfer -Smartparens enables structured editing of s-expressions and other pairs: -#+BEGIN_SRC emacs-lisp - (use-package smartparens - :hook ((prog-mode . smartparens-strict-mode) - (eshell-mode . smartparens-strict-mode) - (vterm-mode . smartparens-mode) - (geiser-repl-mode . smartparens-strict-mode) - (inferior-python-mode . smartparens-strict-mode)) - :init - (defhydra hydra-smartparens (:hint nil) - " - Moving^^^^ Slurp & Barf^^ Wrapping^^ Sexp juggling^^^^ Destructive - ------------------------------------------------------------------------------------------------------------------------ - [_a_] beginning [_n_] down [_h_] bw slurp [_R_] rewrap [_S_] split [_t_] transpose [_c_] change inner [_w_] copy - [_e_] end [_N_] bw down [_H_] bw barf [_u_] unwrap [_s_] splice [_A_] absorb [_C_] change outer - [_f_] forward [_p_] up [_l_] slurp [_U_] bw unwrap [_r_] raise [_E_] emit [_k_] kill [_g_] quit - [_b_] backward [_P_] bw up [_L_] barf [_(__{__[_] wrap (){}[] [_j_] join [_o_] convolute [_K_] bw kill [_q_] quit" - ;; Moving - ("a" sp-beginning-of-sexp) - ("e" sp-end-of-sexp) - ("f" sp-forward-sexp) - ("b" sp-backward-sexp) - ("n" sp-down-sexp) - ("N" sp-backward-down-sexp) - ("p" sp-up-sexp) - ("P" sp-backward-up-sexp) - - ;; Slurping & barfing - ("h" sp-backward-slurp-sexp) - ("H" sp-backward-barf-sexp) - ("l" sp-forward-slurp-sexp) - ("L" sp-forward-barf-sexp) - - ;; Wrapping - ("R" sp-rewrap-sexp) - ("u" sp-unwrap-sexp) - ("U" sp-backward-unwrap-sexp) - ("(" sp-wrap-round) - ("{" sp-wrap-curly) - ("[" sp-wrap-square) - - ;; Sexp juggling - ("S" sp-split-sexp) - ("s" sp-splice-sexp) - ("r" sp-raise-sexp) - ("j" sp-join-sexp) - ("t" sp-transpose-sexp) - ("A" sp-absorb-sexp) - ("E" sp-emit-sexp) - ("o" sp-convolute-sexp) - - ;; Destructive editing - ("c" sp-change-inner :exit t) - ("C" sp-change-enclosing :exit t) - ("k" sp-kill-sexp) - ("K" sp-backward-kill-sexp) - ("w" sp-copy-sexp) - - ("q" nil) - ("g" nil)) - :config - (require 'smartparens-config) - (show-smartparens-global-mode t) - (defun sp-wrap-double-quotes (&optional arg) - (interactive "P") - (sp-wrap-with-pair "\"")) - (defun sp-wrap-single-quotes (&optional arg) - (interactive "P") - (sp-wrap-with-pair "\'")) - (setq sp-ignore-modes-list - (delete 'minibuffer-inactive-mode sp-ignore-modes-list)) - (sp-local-pair 'minibuffer-inactive-mode "\'" nil :actions nil) - :general - (prog-mode-map "C-c p" 'hydra-smartparens/body) - (normal prog-mode-map "g p" 'hydra-smartparens/body) - (normal "g[" 'sp-wrap-square) - (normal "g(" 'sp-wrap-round) - (normal "g{" 'sp-wrap-curly) - (normal "g\"" 'sp-wrap-double-quotes) - (normal "g\'" 'sp-wrap-single-quotes)) - - (use-package evil-smartparens - :after (evil smartparens) - :hook ((smartparens-enabled . evil-smartparens-mode))) - - (jdormit/define-prefix "l" "lisp") - (jdormit/define-prefix "lw" "wrap") - (leader-def-key "lwr" 'sp-wrap-round) - (leader-def-key "lws" 'sp-wrap-square) - (leader-def-key "lwc" 'sp-wrap-curly) - (leader-def-key "ls" 'sp-forward-slurp-sexp) - (leader-def-key "lb" 'sp-forward-barf-sexp) -#+END_SRC - -Enable ES6 arrow functions in web-mode ("borrowed" from [[https://github.com/Fuco1/smartparens/issues/823#issuecomment-403019519][this GitHub comment]]): -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'smartparens - (defun sp-after-equals-p (_id action _context) - (when (memq action '(insert navigate)) - (sp--looking-back-p "=>" 2))) - - (defun sp-after-equals-skip-p (ms mb _me) - (when (eq ms ">") - (save-excursion - (goto-char mb) - (sp--looking-back-p "=" 1)))) - - (sp-local-pair '(web-mode) "<" nil - :unless '(:add sp-after-equals-p) - :skip-match 'sp-after-equals-skip-p)) -#+END_SRC - -Parinfer infers parens from indentation and vice-versa. Currently -disabled since it turned out to be more annoying than good... -#+BEGIN_SRC emacs-lisp - (use-package parinfer - :disabled - :init - (leader-def-key "lt" 'parinfer-toggle-mode) - (setq parinfer-extensions '(defaults - pretty-parens - evil - smart-tab - smart-yank)) - :hook ((clojure-mode . parinfer-mode) - (emacs-lisp-mode . parinfer-mode) - (common-lisp-mode . parinfer-mode) - (scheme-mode . parinfer-mode) - (lisp-mode . parinfer-mode))) -#+END_SRC - -* jq -The JSON multitool. -#+BEGIN_SRC emacs-lisp - (use-package jq-mode - :commands (jq-mode jq-interactively)) -#+END_SRC - -* link-hint -A very helpful package that provides jump-to-link functionality: -#+BEGIN_SRC emacs-lisp - (use-package link-hint - :commands (link-hint-open-link - link-hint-copy-link) - :init - (jdormit/define-prefix "ol" "link-hint") - (leader-def-key "oll" #'link-hint-open-link) - (leader-def-key "olc" #'link-hint-copy-link)) -#+END_SRC - -* Projectile -#+BEGIN_SRC emacs-lisp - (use-package projectile - :hook ((after-init . projectile-mode)) - :commands (projectile-mode - projectile-find-file - projectile-grep - projectile-switch-project - projectile-project-root) - :config - (jdormit/define-prefix "p" "projectile") - (leader-def-key "p" projectile-command-map)) - - (defmacro with-projectile-root (&rest body) - `(with-temp-buffer - (when (projectile-project-root) - (cd (projectile-project-root))) - ,@body)) - #+END_SRC - -* Perspective -A package that groups buffers/windows into workspaces per project: -#+BEGIN_SRC emacs-lisp - (use-package perspective - :commands (persp-mode) - :hook ((after-init . persp-mode)) - :init - (jdormit/define-prefix "v" "perspective") - :config - (leader-def-key "v" perspective-map) - (defun switch-to-previous-buffer () - "Switch to previously open buffer. - Repeated invocations toggle between the two most recently open buffers." - (interactive) - (persp-switch-to-buffer (other-buffer (current-buffer) 1))) - :custom - (persp-sort 'created) - :general - ([remap kill-buffer] #'persp-kill-buffer*) - ([remap switch-to-buffer] #'persp-switch-to-buffer*) - ([remap counsel-switch-buffer] #'persp-counsel-switch-buffer) - ([remap ivy-switch-buffer] #'persp-ivy-switch-buffer)) - - (use-package persp-projectile - :after (perspective projectile) - :demand t - :config - (projectile-persp-bridge counsel-projectile) - (projectile-persp-bridge counsel-projectile-switch-project) - :general - ([remap projectile-switch-project] #'projectile-persp-switch-project)) -#+END_SRC - -* Mode line -* UI -Get rid of the janky buttons: -#+BEGIN_SRC emacs-lisp - (tool-bar-mode -1) -#+END_SRC - -And the menu bar: -#+BEGIN_SRC emacs-lisp - (menu-bar-mode -1) -#+END_SRC - -And the ugly scroll bars: -#+BEGIN_SRC emacs-lisp - (set-scroll-bar-mode nil) -#+END_SRC - -Use =variable-pitch-mode= in text modes: -#+BEGIN_SRC emacs-lisp - (add-hook 'text-mode-hook (lambda () (variable-pitch-mode))) - (add-hook 'w3m-mode-hook (lambda () (variable-pitch-mode))) -#+END_SRC - -Always use =buffer-face-mode= in code and text buffers: -#+BEGIN_SRC emacs-lisp - (add-hook 'prog-mode-hook #'buffer-face-mode) - (add-hook 'text-mode-hook #'buffer-face-mode) -#+END_SRC - -Display the column number in programming modes: -#+BEGIN_SRC emacs-lisp - (add-hook 'prog-mode-hook #'column-number-mode) -#+END_SRC - -Disable the bell: -#+BEGIN_SRC emacs-lisp - (setq ring-bell-function 'ignore) -#+END_SRC - - -Render stuff differently based on whether or not we are graphical: -#+BEGIN_SRC emacs-lisp - (defun graphical-setup () - (when (display-graphic-p (selected-frame)) - (message "Running graphically"))) - - (defun non-graphical-setup () - (when (not (display-graphic-p (selected-frame))) - (message "Running in terminal") - (menu-bar-mode -1))) - - (defun do-graphical-non-graphical-setup () - (graphical-setup) - (non-graphical-setup)) - - (add-hook 'window-setup-hook #'do-graphical-non-graphical-setup) -#+END_SRC - -Try to make the background normal colored in the terminal: -#+BEGIN_SRC emacs-lisp - (defvar no-background-in-tty-faces '(default line-number magit-section-highlight)) - - (defun on-frame-open (frame) - (unless (display-graphic-p frame) - (menu-bar-mode -1) - (dolist (face no-background-in-tty-faces) - (set-face-background face "unspecified" frame)))) - - (mapc #'on-frame-open (frame-list)) - - (add-hook 'after-make-frame-functions #'on-frame-open) - - (defun on-after-init () - (unless (display-graphic-p (selected-frame)) - (dolist (face no-background-in-tty-faces) - (set-face-background face "unspecified" (selected-frame))))) - - (add-hook 'window-setup-hook #'on-after-init) -#+END_SRC - -UI-related keybindings: -#+BEGIN_SRC emacs-lisp - (jdormit/define-prefix "u" "UI") - (leader-def-key "ut" #'customize-themes) - (leader-def-key "uf" #'customize-face) - (leader-def-key "uc" #'display-time-mode) - (leader-def-key "ub" #'display-battery-mode) -#+END_SRC - -* Window handling -Following [[https://github.com/nex3/perspective-el#some-musings-on-emacs-window-layouts][some excellent advice]] from the author of perspective.el -about making Emacs' window handling saner: -#+BEGIN_SRC emacs-lisp - (setq display-buffer-alist - '((".*" (display-buffer-reuse-window display-buffer-same-window)))) - - (setq display-buffer-reuse-frames t) ; reuse windows in other frames - (setq even-window-sizes nil) ; display-buffer: avoid resizing -#+END_SRC - -* Centaur tabs -[[https://github.com/ema2159/centaur-tabs][Centaur tabs]] is a package that gives Emacs buffer tabs similar to those in Atom or VS Code: -#+BEGIN_SRC emacs-lisp - (use-package centaur-tabs - :commands (centaur-tabs-mode - centaur-tabs-local-mode - centaur-tabs-mode-on-p) - :init - (setq centaur-tabs-set-icons t - centaur-tabs-gray-out-icons 'buffer - centaur-tabs-height 30 - centaur-tabs-set-bar 'under - x-underline-at-descent-line t - centaur-tabs-set-modified-marker t - centaur-tabs-show-navigation-buttons t - centaur-tabs-down-tab-text " ☰ " - centaur-tabs-backward-tab-text " ◀ " - centaur-tabs-forward-tab-text " ▶ " - centaur-tabs-close-button "✕" - centaur-tabs-modified-marker "⬤" - centaur-tabs-cycle-scope 'tabs - centaur-tabs-label-fixed-length 20) - (leader-def-key "uT" #'centaur-tabs-mode) - (centaur-tabs-mode) - :config - (centaur-tabs-group-by-projectile-project) - - ;; Custom buffer groups - (defun centaur-tabs-projectile-buffer-groups () - "Return the list of group names BUFFER belongs to." - (if centaur-tabs-projectile-buffer-group-calc - (symbol-value 'centaur-tabs-projectile-buffer-group-calc) - (set (make-local-variable 'centaur-tabs-projectile-buffer-group-calc) - - (cond - ((or (get-buffer-process (current-buffer)) - (memq major-mode '(comint-mode compilation-mode))) '("Term")) - ((string-equal "*" (substring (buffer-name) 0 1)) '("Misc")) - ((condition-case _err - (projectile-project-root) - (error nil)) (list (projectile-project-name))) - ((memq major-mode '(emacs-lisp-mode python-mode emacs-lisp-mode c-mode - c++-mode javascript-mode js-mode - js2-mode makefile-mode - lua-mode vala-mode)) '("Coding")) - ((memq major-mode '(nxhtml-mode html-mode - mhtml-mode css-mode)) '("HTML")) - ((memq major-mode '(org-journal-mode)) '("Journal")) - ((memq major-mode '(org-mode calendar-mode diary-mode)) '("Org")) - ((memq major-mode '(dired-mode)) '("Dir")) - (t '("Other")))) - (symbol-value 'centaur-tabs-projectile-buffer-group-calc))) - - ;; Don't show tabs for certain types of buffers - (advice-add 'centaur-tabs-hide-tab :around - (lambda (oldfn buf &rest args) - (if (with-current-buffer buf - (or (eq major-mode 'vuiet-mode) - (eq major-mode 'dired-sidebar-mode))) - t - (apply oldfn buf args)))) - - ;; Only show tabs in buffers visiting files - (advice-add 'centaur-tabs-line :around - (lambda (oldfn &rest args) - (if (buffer-file-name) - (apply oldfn args) - (setq header-line-format nil)))) - - ;; Enable prefix argument for tab switching keybindings - (advice-add 'centaur-tabs-forward :around - (lambda (oldfn &rest args) - (if (numberp current-prefix-arg) - (dotimes (_ current-prefix-arg) - (apply oldfn args)) - (apply oldfn args)))) - (advice-add 'centaur-tabs-backward :around - (lambda (oldfn &rest args) - (if (numberp current-prefix-arg) - (dotimes (_ current-prefix-arg) - (apply oldfn args)) - (apply oldfn args)))) - - ;; Use Org-mode titles for tab names when possible - (advice-add 'centaur-tabs-buffer-tab-label :around - (lambda (oldfn tab &rest args) - (if-let ((title (or (and - (fboundp 'org-roam-db--get-titles) - (car - (org-roam-db--get-titles - (buffer-file-name (car tab))))) - (org-get-title - (with-current-buffer (car tab) - (buffer-substring (point-min) - (min (point-max) 200))))))) - (if (> centaur-tabs-label-fixed-length 0) - (centaur-tabs-truncate-string centaur-tabs-label-fixed-length - (format " %s" title)) - (format " %s" title)) - (apply oldfn tab args)))) - - ;; Add a cache to speed up icon rendering for huge groups - (defvar centaur-tabs-icon-cache (make-hash-table :test 'equal) - "A cache holding icons generated for centaur-tabs mode tabs.") - (advice-add 'centaur-tabs-icon :around - (lambda (oldfn tab face selected &rest args) - (let ((key (list tab face selected))) - (or (gethash key centaur-tabs-icon-cache) - (puthash key - (apply oldfn tab face selected args) - centaur-tabs-icon-cache))))) - - :general - ((normal motion visual) "g t" #'centaur-tabs-forward) - ((normal motion visual) "g T" #'centaur-tabs-backward) - (leader-map "pt" #'centaur-tabs-counsel-switch-group) - :hook - (git-commit-mode . (lambda () - (when (centaur-tabs-mode-on-p) - (centaur-tabs-local-mode))))) -#+END_SRC - -* Frame parameters -Functions to change the frame size: -#+BEGIN_SRC emacs-lisp - (defun jdormit/set-frame-size (width height) - (interactive "nWidth: \nnHeight: ") - (if (display-graphic-p) - (set-frame-size (selected-frame) width height) - (message "Not running graphically"))) - - (defun jdormit/set-frame-width (width) - (interactive "nWidth: ") - (jdormit/set-frame-size width (frame-height))) - - (defun jdormit/set-frame-height (height) - (interactive "nHeight: ") - (jdormit/set-frame-size (frame-width) height)) -#+END_SRC - -Keybindings: -#+BEGIN_SRC emacs-lisp - (leader-def-key "Fw" 'jdormit/set-frame-width) - (leader-def-key "Fh" 'jdormit/set-frame-height) - (leader-def-key "Fs" 'jdormit/set-frame-size) -#+END_SRC - -* Transpose Frame -A handy utility that reverse the current frame window split (vertical to horizontal or vice-versa): -#+BEGIN_SRC emacs-lisp - (use-package transpose-frame - :defer t - :init - (leader-def-key "wt" 'transpose-frame)) -#+END_SRC - -* EShell -Easy keybinding to open EShell: -#+BEGIN_SRC emacs-lisp - (defun open-eshell (&optional arg) - (interactive "P") - (if (and (fboundp 'projectile-project-root) - (projectile-project-root)) - (projectile-run-eshell arg) - (eshell arg))) - - (leader-def-key "'" 'open-eshell) -#+END_SRC - -Make EShell's tab completion work like Bash's: -#+BEGIN_SRC emacs-lisp - (setq eshell-cmpl-cycle-completions nil) -#+END_SRC - -Add additional useful modules: -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'esh-module - (add-to-list 'eshell-modules-list 'eshell-tramp)) - - (with-eval-after-load 'eshell - (require 'esh-module)) -#+END_SRC - -Prefer Lisp commands to external programs: -#+BEGIN_SRC emacs-lisp - (setq eshell-prefer-lisp-functions t - eshell-prefer-lisp-variables t) -#+END_SRC - -Enable password caching: -#+BEGIN_SRC emacs-lisp - (setq password-cache t - password-cache-expiry 120) -#+END_SRC - -Destroy shell buffers created by eshell when the process dies:: -#+BEGIN_SRC emacs-lisp - (setq eshell-destroy-buffer-when-process-dies t) -#+END_SRC - -Visual programs: -#+BEGIN_SRC emacs-lisp - (defun eshell-setup () - (add-to-list 'eshell-visual-commands "crawl") - (add-to-list 'eshell-visual-commands "ssh") - (add-to-list 'eshell-visual-commands "watch") - (add-to-list 'eshell-visual-subcommands '("kubectl" "exec")) - (add-to-list 'eshell-visual-subcommands '("k" "exec")) - (add-to-list 'eshell-visual-subcommands '("docker" "build")) - (add-to-list 'eshell-visual-subcommands '("docker" "push"))) - - (add-hook 'eshell-mode-hook #'eshell-setup) -#+END_SRC - -And a function to run any program visually: -#+BEGIN_SRC emacs-lisp - (defun eshell/v (&rest args) - (apply #'eshell-exec-visual args)) -#+END_SRC - -Load .dir-locals.el when switching directories: -#+BEGIN_SRC emacs-lisp - (add-hook 'eshell-mode-hook #'hack-dir-local-variables-non-file-buffer) - (add-hook 'eshell-after-prompt-hook #'hack-dir-local-variables-non-file-buffer) -#+END_SRC - -A function to properly clear the eshell: -#+BEGIN_SRC emacs-lisp - (defun clear-eshell (&optional prefix) - (interactive) - (let ((input (eshell-get-old-input))) - (eshell/clear-scrollback) - (eshell-emit-prompt) - (insert input))) - - (add-hook 'eshell-mode-hook - (lambda () (general-def eshell-mode-map "C-c C-o" #'clear-eshell))) -#+END_SRC - -Compilation-shell-minor-mode: -#+BEGIN_SRC emacs-lisp - (add-hook 'eshell-mode-hook #'compilation-shell-minor-mode) -#+END_SRC - - -** Prompt -#+BEGIN_SRC emacs-lisp - (defun jdormit-eshell-prompt () - (let ((branch (magit-name-local-branch "HEAD"))) - (format "%s%s" - (if branch (format "(%s) " branch) "") - (concat (abbreviate-file-name (eshell/pwd)) - " " - (propertize - (if (= (user-uid) 0) "#" "λ") - 'face `(:foreground "#859900")) - " ")))) - - (setq jdormit-eshell-prompt-regex "^[^#λ\n]* [#λ] ") - - (setq eshell-prompt-function 'jdormit-eshell-prompt) - (setq eshell-prompt-regexp jdormit-eshell-prompt-regex) -#+END_SRC - -* Flycheck -Syntax checking etc.: -#+BEGIN_SRC emacs-lisp - (use-package flycheck - :init - (defhydra hydra-flycheck - (:pre (flycheck-list-errors) - :post (quit-windows-on "*Flycheck errors*") - :hint nil) - "Errors" - ("f" flycheck-error-list-set-filter "Filter") - ("j" flycheck-next-error "Next") - ("k" flycheck-previous-error "Previous") - ("gg" flycheck-first-error "First") - ("G" (progn (goto-char (point-max)) (flycheck-previous-error)) "Last") - ("q" nil)) - :config - (setq-default flycheck-disabled-checkers '(emacs-lisp emacs-lisp-checkdoc)) - (global-flycheck-mode) - :general - ((normal motion visual) flycheck-mode-map "ze" 'hydra-flycheck/body)) -#+END_SRC - -* Tabs -#+BEGIN_SRC emacs-lisp - (defun disable-tab-insert () - (interactive) - (setq indent-tabs-mode nil)) -#+END_SRC - -* aggressive-indent-mode -Like [[help:electric-indent-mode][electric-indent-mode]] but reindents after every change: -#+BEGIN_SRC emacs-lisp - (use-package aggressive-indent - :hook ((clojure-mode . aggressive-indent-mode) - (emacs-lisp-mode . aggressive-indent-mode) - (lisp-mode . aggressive-indent-mode) - (scheme-mode . aggressive-indent-mode))) -#+END_SRC - -* Indentation guides -#+BEGIN_SRC emacs-lisp - (use-package highlight-indent-guides - :commands highlight-indent-guides-mode - :hook ((python-mode . highlight-indent-guides-mode) - (yaml-mode . highlight-indent-guides-mode)) - :init - (leader-def-key "th" #'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)) -#+END_SRC - -* JSON -#+BEGIN_SRC emacs-lisp - (use-package json-mode - :mode (("\\.json\\'" . json-mode)) - :config - (setq js-indent-level 2)) - - (use-package json-navigator - :commands (json-navigator-navigator - json-navigator-navigate-after-point - json-navigator-navigate-region)) - - (use-package tree-mode - :general - (normal tree-mode-map - "D" #'tree-mode-delete-tree - "k" #'tree-mode-previous-node - "j" #'tree-mode-next-node - "l" #'tree-mode-next-sib - "h" #'tree-mode-previous-sib - "u" #'tree-mode-goto-parent - "r" #'tree-mode-goto-root - "gr" #'tree-mode-reflesh - "E" #'tree-mode-expand-level - "e" #'tree-mode-toggle-expand - "s" #'tree-mode-sort-by-tag - "/" #'tree-mode-keep-match - "!" #'tree-mode-collapse-other-except) - :hook - ((json-navigator-mode . tree-minor-mode))) - - (defun json-pprint () - (interactive) - (let ((begin (if (region-active-p) (region-beginning) (point-min))) - (end (if (region-active-p) (region-end) (point-max)))) - (if (executable-find "jq") - (shell-command-on-region begin end "jq ." nil t) - (json-pretty-print begin end)))) - - (general-def json-mode-map "C-M-\\" 'json-pprint) -#+END_SRC - -* JavaScript -Some formatting stuff: -#+BEGIN_SRC emacs-lisp - (setq js-indent-level 4) -#+END_SRC - -#+BEGIN_SRC emacs-lisp - (use-package web-mode - :mode (("\\.html\\'" . web-mode) - ("\\.js\\'" . web-mode) - ("\\.jsx\\'" . web-mode) - ("\\.mako\\'" . web-mode) - ("\\.jinja2\\'" . web-mode) - ("\\.hbs\\'" . web-mode)) - :config - (setq web-mode-engines-alist - '(("django" . "\\.jinja2\\'"))) - (add-hook 'web-mode-hook - (lambda () - (when (equal web-mode-content-type "javascript") - (web-mode-set-content-type "jsx")) - (when (or (equal web-mode-content-type "javascript") - (equal web-mode-content-type "jsx")) - (lsp-deferred)))) - (add-hook 'web-mode-hook #'disable-tab-insert) - :custom - (web-mode-enable-auto-pairing nil)) -#+END_SRC - -Use nvm to manage node versions: -#+BEGIN_SRC emacs-lisp - (use-package nvm - :straight (nvm :host github :repo "rejeep/nvm.el") - :commands (nvm-use nvm-use-for nvm-use-for-buffer)) -#+END_SRC - -A command to format JS via prettier: -#+BEGIN_SRC emacs-lisp - (defun prettier () - (interactive) - (let ((start (if (use-region-p) (region-beginning) (point-min))) - (end (if (use-region-p) (region-end) (point-max))) - (parser (cond - ((eq major-mode 'graphql-mode) "graphql") - (t "babel")))) - (shell-command-on-region start end (concat "prettier --parser " parser) nil t))) -#+END_SRC - -** NVM -Manage node version via NVM within Emacs: -#+BEGIN_SRC emacs-lisp - (use-package nvm - :commands (nvm-use - nvm-use-for - nvm-use-for-buffer - nvm--installed-versions) - :init - (defun nvm (version) - (interactive (list - (completing-read "Node version: " - (mapcar #'car - (nvm--installed-versions))))) - (nvm-use version))) -#+END_SRC - -* Java -#+BEGIN_SRC emacs-lisp - (use-package lsp-java - :hook ((java-mode . lsp-deferred))) -#+END_SRC - -* Kotlin -#+BEGIN_SRC emacs-lisp - (use-package kotlin-mode - :mode (("\\.kt\\'" . kotlin-mode)) - :config - (with-eval-after-load 'lsp - (when (executable-find "kotlin-language-server") - (add-hook 'kotlin-mode-hook #'lsp-deferred)))) -#+END_SRC - -* Groovy -Used for Jenkins configuration scripts and probably other things. -#+BEGIN_SRC emacs-lisp - (use-package groovy-mode - :commands (groovy-mode) - :mode (("\\.groovy\\'" . groovy-mode)) - :init - (add-to-list 'interpreter-mode-alist - '("groovy" . groovy-mode)) - :custom - (groovy-indent-offset 2)) -#+END_SRC - -* Typescript -#+BEGIN_SRC emacs-lisp - (use-package typescript-mode - :mode ("\\.ts\\'") - :config - (with-eval-after-load 'lsp - (add-hook 'typescript-mode-hook 'lsp-deferred))) -#+END_SRC - -* LSP Mode -Emacs support for the Language Server Protocol - -#+BEGIN_SRC emacs-lisp - (use-package lsp-mode - :defer t - :init - (defhydra hydra-lsp (:exit t :hint nil) - " - Buffer^^ Server^^ Symbol - ------------------------------------------------------------------------------------- - [_f_] format [_M-r_] restart [_d_] declaration [_i_] implementation [_o_] documentation - [_m_] imenu [_S_] shutdown [_D_] definition [_t_] type [_r_] rename - [_x_] execute action [_M-s_] describe session [_R_] references [_s_] signature" - ("d" lsp-find-declaration) - ("D" lsp-ui-peek-find-definitions) - ("R" lsp-ui-peek-find-references) - ("i" lsp-ui-peek-find-implementation) - ("t" lsp-find-type-definition) - ("s" lsp-signature-help) - ("o" lsp-describe-thing-at-point) - ("r" lsp-rename) - - ("f" lsp-format-buffer) - ("m" lsp-ui-imenu) - ("x" lsp-execute-code-action) - - ("M-s" lsp-describe-session) - ("M-r" lsp-restart-workspace) - ("S" lsp-shutdown-workspace)) - :general - (lsp-mode-map "C-c h" 'hydra-lsp/body) - ((normal visual motion) lsp-mode-map "K" #'lsp-describe-thing-at-point) - :hook - ((lsp-mode . (lambda () - (let ((lsp-keymap-prefix "gl")) - (lsp-enable-which-key-integration))))) - :config - (setq lsp-prefer-flymake nil) - (general-def '(normal visual motion) "gl" lsp-command-map) - :commands lsp-mode lsp lsp-deferred - :custom - (lsp-enable-snippet nil) - (lsp-eldoc-render-all nil) - (lsp-headerline-breadcrumb-enable nil) - (lsp-file-watch-threshold 100000)) - - (use-package lsp-ui - :after (lsp-mode) - :custom - (lsp-ui-sideline-enable t) - (lsp-ui-sideline-show-symbol t) - (lsp-ui-sideline-show-hover t) - (lsp-ui-sideline-show-code-actions t) - (lsp-ui-sideline-update-mode 'point) - (lsp-ui-doc-alignment 'window) - (lsp-ui-doc-header t) - (lsp-ui-doc-position 'top) - (lsp-ui-doc-background '((t (:inherit region)))) - (lsp-ui-doc-header '((t (:inherit lsp-face-highlight-write)))) - (lsp-ui-sideline-current-symbol '((t (:inherit font-lock-constant-face - :weight ultra-bold))))) - - (with-eval-after-load 'lsp-clients - (defun lsp-typescript-javascript-tsx-jsx-activate-p (filename major-mode) - "Checks if the javascript-typescript language server should be enabled - based on FILE-NAME and MAJOR-MODE" - (or (member major-mode '(typescript-mode typescript-tsx-mode js-mode js2-mode rjsx-mode)) - (and (eq major-mode 'web-mode) - (or (string-suffix-p ".tsx" filename t) - (string-suffix-p ".jsx" filename t) - (string-suffix-p ".js" filename t)))))) -#+END_SRC - -* Python -** General -#+BEGIN_SRC emacs-lisp - (leader-def-key "sp" #'run-python) - (add-hook 'python-mode-hook #'disable-tab-insert) -#+END_SRC - -ISort is a Python utility to sort imports: -#+BEGIN_SRC emacs-lisp - (use-package py-isort - :commands (py-isort-buffer py-isort-region) - :config - (setq py-isort-options '("-m=3")) - :general - (python-mode-map "C-c C-i" #'py-isort-buffer)) -#+END_SRC - -Run black on the current buffer: -#+BEGIN_SRC emacs-lisp - (general-def 'normal python-mode-map "C-M-\\" #'format-all-buffer) -#+END_SRC - -[[https://github.com/naiquevin/sphinx-doc.el][sphinx-doc.el]] automatically generates doc strings for Python functions (and updates existing ones!): -#+BEGIN_SRC emacs-lisp - (use-package sphinx-doc - :hook ((python-mode . sphinx-doc-mode))) -#+END_SRC - -** Dev environment/IDE stuff -Support pyvenv within Emacs: -#+BEGIN_SRC emacs-lisp - (use-package pyvenv - :defer 0 - :commands (pyvenv-mode - pyvenv-tracking-mode - pyvenv-workon - pyvenv-activate - pyvenv-track-virtualenv) - :config - (pyvenv-mode) - (pyvenv-tracking-mode)) - - (defun eshell/workon (name) - (pyvenv-workon name)) - - (defun eshell/activate (dir) - (pyvenv-activate dir)) - - (defun eshell/deactivate () - (pyvenv-deactivate)) -#+END_SRC - -And support pyenv (NOT pyvenv) to change Python versions: -#+BEGIN_SRC emacs-lisp - (use-package pyenv-mode - :defer t) -#+END_SRC - -Use the LSP python client: -#+BEGIN_SRC emacs-lisp - (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) - ('normal python-mode-map "K" #'lsp-describe-thing-at-point)) -#+END_SRC - -Override the flycheck python-mypy checker to run in the right -directory: -#+BEGIN_SRC emacs-lisp - (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) - (projectile-compilation-dir))) -#+END_SRC - - -** Autoflake -[[https://pypi.org/project/autoflake/][Autoflake]] is a tool that removes unused imports and variables from Python code: -#+BEGIN_SRC emacs-lisp - (defvar autoflake-args '() - "Arguments to pass to the autoflake command. - - See URL `https://pypi.org/project/autoflake' for options.") - - (defun autoflake (arg) - (interactive "P") - (let ((autoflake-cmd (or (executable-find "autoflake") - (error "Autoflake executable not found"))) - (file (cond - ((or arg (not buffer-file-name)) - (read-file-name "Run autoflake on file: ")) - (buffer-file-name buffer-file-name) - (:else (error "Invalid file for autoflake"))))) - (apply #'call-process autoflake-cmd nil nil nil - (append autoflake-args (list "--in-place" file))))) -#+END_SRC - -** Testing -[[https://github.com/wbolster/emacs-python-pytest][python-pytest.el]] integrates Pytest with Emacs: -#+BEGIN_SRC emacs-lisp - (use-package python-pytest - :commands (python-pytest-popup - python-pytest--current-defun) - :general - (python-mode-map "C-c t p" #'python-pytest-popup) - ((normal motion visual) python-pytest-mode-map "g r" #'python-pytest-repeat) - ((normal motion visual) python-pytest-mode-map "q" #'quit-window)) -#+END_SRC - -And borrowing some functions from python-pytest, we can get some nosetests support as well: -#+BEGIN_SRC emacs-lisp - (defvar nosetests-args "" - "Additional args to pass to nosetests") - - (defun run-nose (args &optional debug) - "Runs nosetests with `args' - - If `debug' is non-nil, run in a GUD PDB session." - (let* ((nosetests-cmd (executable-find "nosetests")) - (cmdline (format "%s %s" nosetests-cmd args))) - (when (not nosetests-cmd) - (user-error "Nosetests command not found")) - (if debug - (realgud:pdb cmdline) - (compile cmdline)))) - - (defun run-nose-reading-args (arg nose-args &optional debug) - "Runs nosetests with default args or prompts for args with prefix - - If `debug' is non-nil, run in a GUD PDB session." - (let ((args (if arg - (read-string "Nosetests arguments: " - nil nil nosetests-args) - nosetests-args))) - (run-nose (format "%s %s" args nose-args) debug))) - - (defun run-nose-in-project (arg nose-args &optional debug) - "Runs nosetests from the project root - - If `debug' is non-nil, run in a GUD PDB session." - (let ((dir (or (projectile-project-root) - default-directory))) - (with-temp-buffer - (cd dir) - (run-nose-reading-args arg nose-args debug)))) - - (defun nosetests-all (arg) - "Runs nosetests on all project tests, prompting for the tests directory" - (interactive "P") - (let ((test-dir (read-file-name "Test directory: " - (or (projectile-project-root) - default-directory) - nil t "tests" #'directory-name-p))) - (run-nose-in-project arg (directory-file-name test-dir)))) - - (defun nosetests-debug-all (arg) - "Runs nosetests in a GUD session on all project tests" - (interactive "P") - (let ((test-dir (read-file-name "Test directory: " - (or (projectile-project-root) - default-directory) - nil t "tests" #'directory-name-p))) - (run-nose-in-project arg (directory-file-name test-dir) t))) - - (defun nosetests-module (arg module) - "Runs nosetests in the module of the current file" - (interactive (list current-prefix-arg - (read-file-name "Run nosetests on module: " - nil nil t - (file-name-directory - (buffer-file-name)) - #'directory-name-p))) - (run-nose-in-project arg (directory-file-name module))) - - (defun nosetests-debug-module (arg module) - "Runs nosetests in a GUD session in the module of the current file" - (interactive (list current-prefix-arg - (read-file-name "Run nosetests on module: " - nil nil t - (file-name-directory - (buffer-file-name)) - #'directory-name-p))) - (run-nose-in-project arg (directory-file-name module) t)) - - (defun nosetests-file (arg file) - "Runs nosetests on the current file" - (interactive (list current-prefix-arg - (read-file-name "Run nosetests on file: " - nil nil t (buffer-file-name)))) - (run-nose-in-project arg file)) - - (defun nosetests-debug-file (arg file) - "Runs nosetests in a GUD session on the current file" - (interactive (list current-prefix-arg - (read-file-name "Run nosetests on file: " - nil nil t (buffer-file-name)))) - (run-nose-in-project arg file t)) - - (defun nosetests-def (arg def) - "Runs nosetests on the enclosing function at point" - (interactive (list current-prefix-arg - (python-pytest--current-defun))) - (run-nose-in-project arg (format "%s:%s" - (buffer-file-name) - def))) - - (defun nosetests-debug-def (arg def) - "Runs nosetests in a GUD session on the enclosing function at point" - (interactive (list current-prefix-arg - (python-pytest--current-defun))) - (run-nose-in-project arg - (format "%s:%s" - (buffer-file-name) - def) - t)) - - (defvar nosetests-map (make-sparse-keymap) - "Keymap for nosetests") - - (defvar nosetests-debug-map (make-sparse-keymap) - "Keymap for debugging nosetests") - - (general-def python-mode-map "C-c t n" nosetests-map) - (general-def nosetests-map "a" #'nosetests-all) - (general-def nosetests-map "m" #'nosetests-module) - (general-def nosetests-map "f" #'nosetests-file) - (general-def nosetests-map "d" #'nosetests-def) - (general-def nosetests-map "b" nosetests-debug-map) - - (general-def nosetests-debug-map "a" #'nosetests-debug-all) - (general-def nosetests-debug-map "m" #'nosetests-debug-module) - (general-def nosetests-debug-map "f" #'nosetests-debug-file) - (general-def nosetests-debug-map "d" #'nosetests-debug-def) - - (which-key-add-major-mode-key-based-replacements - 'python-mode "C-c t n" "nosetests") - (which-key-add-major-mode-key-based-replacements - 'python-mode "C-c t n b" "debug") -#+END_SRC - -* Hy -Python but Lispy! - -#+BEGIN_SRC emacs-lisp - (defun run-hy () - (interactive) - (run-lisp (expand-file-name "~/.virtualenvs/hy/bin/hy"))) -#+END_SRC - -* Go -Basic support: -#+BEGIN_SRC emacs-lisp - (use-package go-mode - :mode (("\\.go\\'" . go-mode))) -#+END_SRC - -LSP support - requires [[https://github.com/sourcegraph/go-langserver][go-langserver]]. -#+BEGIN_SRC emacs-lisp - (add-hook 'go-mode-hook #'lsp-deferred) -#+END_SRC - -* Clojure -Start with clojure-mode: -#+BEGIN_SRC emacs-lisp - (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))) -#+END_SRC - -Add flycheck support: -#+BEGIN_SRC emacs-lisp - (use-package flycheck-clj-kondo - :after (clojure-mode) - :if (executable-find "clj-kondo") - :ensure t) -#+END_SRC - -Sprinkle in some CIDER: -#+BEGIN_SRC emacs-lisp - (use-package cider - :commands (cider-mode cider-jack-in cider-jack-in-clojurescript) - :config - (setq cider-known-endpoints - '(("local" "localhost" "4005")) - cider-prompt-for-symbol nil) - (general-def cider-mode-map "C-c t" cider-test-commands-map) - (add-hook 'cider-repl-mode-hook 'smartparens-strict-mode) - :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)) - - (defun jdormit/cider-setup () - (local-set-key (kbd "C-c M-b") 'cider-debug-defun-at-point)) - - (add-hook 'cider-mode-hook 'jdormit/cider-setup) -#+END_SRC - -Add some handy hydras: -#+BEGIN_SRC emacs-lisp - (use-package cider-hydra - :after (cider) - :hook ((cider-mode . cider-hydra-mode))) -#+END_SRC - -Clj-refactor adds magical refactoring abilities: -#+BEGIN_SRC emacs-lisp - (use-package clj-refactor - :init - (defun clj-refactor-setup () - (interactive) - (clj-refactor-mode 1) - (cljr-add-keybindings-with-prefix "C-c r")) - :config - (setq cljr-auto-sort-ns t) - :hook ((clojure-mode . clj-refactor-setup))) -#+END_SRC - -Add support for running Org-mode Clojure source blocks with [[https://github.com/borkdude/babashka][Babashka]]: -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'ob-clojure - (defcustom org-babel-clojure-backend nil - "Backend used to evaluate Clojure code blocks." - :group 'org-babel - :type '(choice - (const :tag "inf-clojure" inf-clojure) - (const :tag "cider" cider) - (const :tag "slime" slime) - (const :tag "bb" bb) - (const :tag "Not configured yet" nil))) - - (defun elisp->clj (in) - (cond - ((listp in) (concat "[" (s-join " " (mapcar #'elisp->clj in)) "]")) - (t (format "%s" in)))) - - (defun ob-clojure-eval-with-bb (expanded params) - "Evaluate EXPANDED code block with PARAMS using babashka." - (unless (executable-find "bb") - (user-error "Babashka not installed")) - (let* ((stdin (let ((stdin (cdr (assq :stdin params)))) - (when stdin - (elisp->clj - (org-babel-ref-resolve stdin))))) - (input (cdr (assq :input params))) - (file (make-temp-file "ob-clojure-bb" nil nil expanded)) - (command (concat (when stdin (format "echo %s | " (shell-quote-argument stdin))) - (format "bb %s -f %s" - (cond - ((equal input "edn") "") - ((equal input "text") "-i") - (t "")) - (shell-quote-argument file)))) - (result (shell-command-to-string command))) - (s-trim result))) - - (defun org-babel-execute:clojure (body params) - "Execute a block of Clojure code with Babel." - (let* ((org-babel-clojure-backend (or (cdr (assq :backend params)) - org-babel-clojure-backend)) - (org-babel-clojure-backend (when org-babel-clojure-backend - (intern org-babel-clojure-backend)))) - (unless org-babel-clojure-backend - (user-error "You need to customize org-babel-clojure-backend")) - (let* ((expanded (org-babel-expand-body:clojure body params)) - (result-params (cdr (assq :result-params params))) - result) - (setq result - (cond - ((eq org-babel-clojure-backend 'inf-clojure) - (ob-clojure-eval-with-inf-clojure expanded params)) - ((eq org-babel-clojure-backend 'cider) - (ob-clojure-eval-with-cider expanded params)) - ((eq org-babel-clojure-backend 'slime) - (ob-clojure-eval-with-slime expanded params)) - ((eq org-babel-clojure-backend 'bb) - (ob-clojure-eval-with-bb expanded params)))) - (org-babel-result-cond result-params - result - (condition-case nil (org-babel-script-escape result) - (error result)))))) - - (customize-set-variable 'org-babel-clojure-backend 'bb)) - - (add-hook 'org-mode-hook (lambda () (require 'ob-clojure))) -#+END_SRC - -* Scheme -Tell emacs about file extensions which should activate scheme-mode: -#+BEGIN_SRC emacs-lisp - (add-to-list 'auto-mode-alist '("\\.guile\\'" . scheme-mode)) - (add-to-list 'auto-mode-alist '("\\.rkt\\'" . scheme-mode)) -#+END_SRC -[[http://www.nongnu.org/geiser/geiser_1.html][Geiser]] is a Scheme IDE for Emacs that supports a bunch of common Scheme implementations. -#+BEGIN_SRC emacs-lisp - (use-package geiser - :commands (run-geiser) - :config - (setq geiser-active-implementations - (cl-reduce (lambda (acc val) - (if (executable-find (symbol-name val)) - (cons val acc) - acc)) - '(guile racket chicken chez mit chibi gambit) - :initial-value nil)) - :general - (geiser-mode-map 'normal - "M-." 'geiser-edit-symbol-at-point - "M-," 'geiser-pop-symbol-stack) - (geiser-debug-mode-map "SPC" leader-map)) -#+END_SRC - -And a handy shortcut to hop into a Geiser REPL: -#+BEGIN_SRC emacs-lisp - (leader-def-key "sg" 'run-geiser) -#+END_SRC - -* Common Lisp -[[https://common-lisp.net/project/slime/][SLIME]] is a set of modes and utilities for writing Common Lisp in Emacs. [[https://www.quicklisp.org/beta/][Quicklisp]] is the de-facto Common Lisp package manager. It comes with some Emacs bindings. -#+BEGIN_SRC emacs-lisp - (use-package slime-company - :after (slime)) - - (use-package slime - :commands (slime) - :config - (setq inferior-lisp-program - (executable-find "sbcl") - slime-contribs '(slime-repl - slime-fancy - slime-company)) - (when (file-exists-p - (expand-file-name "~/quicklisp/slime-helper.el")) - (load (expand-file-name "~/quicklisp/slime-helper.el"))) - (add-hook 'slime-repl-mode-hook 'smartparens-strict-mode) - (add-to-list 'browse-url-browser-function - '("lispworks.com/documentation/HyperSpec" . w3m-browse-url)) - :general - ((normal motion visual insert emacs) slime-mode-map "M-." #'slime-edit-definition)) - - (add-to-list 'auto-mode-alist '("\\.cl\\'" . lisp-mode)) -#+END_SRC - -Keyboard shortcut to start a SLIME REPL: -#+BEGIN_SRC emacs-lisp - (leader-def-key "sc" 'slime) -#+END_SRC - -* Haskell -#+BEGIN_SRC emacs-lisp - (defun jdormit/haskell-setup () - (local-set-key (kbd "C-c M-j") 'interactive-haskell-mode)) - (use-package haskell-mode - :mode (("\\.hs\\'" . haskell-mode))) - (add-hook 'haskell-mode-hook 'jdormit/haskell-setup) -#+END_SRC - -* PHP -#+BEGIN_SRC emacs-lisp - (use-package php-mode - :mode "\\.php\\'") - - (use-package mmm-mode - :after php-mode) -#+END_SRC - -Geben is an interface to XDebug allowing debugging PHP in Emacs: -#+BEGIN_SRC emacs-lisp - (use-package geben - :commands (geben)) -#+END_SRC - -Some keybindings to start and end Geben: -#+BEGIN_SRC emacs-lisp - (general-def php-mode-map "C-c C-d" #'geben) - (general-def php-mode-map "C-c C-q" #'geben-end) -#+END_SRC - -LSP for PHP requires [[https://github.com/felixfbecker/php-language-server][php-language-server]] to be installed in ~/.composer: -#+BEGIN_SRC emacs-lisp - (add-hook 'php-mode-hook #'lsp-deferred) -#+END_SRC - -* YAML -#+BEGIN_SRC emacs-lisp - (use-package yaml-mode - :mode ("//.yml//'")) -#+END_SRC - -* Pharen -[[https://pharen.org][Pharen]] is a Lisp that compiles to PHP. It looks a lot like Clojure. -#+BEGIN_SRC emacs-lisp - (add-to-list 'auto-mode-alist '("\\.phn\\'" . clojure-mode)) -#+END_SRC - -* Bash -Use LSP if [[https://github.com/mads-hartmann/bash-language-server][bash-language-server]] is installed. -#+BEGIN_SRC emacs-lisp - (when (executable-find "bash-language-server") - (add-hook 'sh-mode-hook #'lsp-deferred)) -#+END_SRC - -* Ruby -#+BEGIN_SRC emacs-lisp - (add-hook 'ruby-mode-hook #'lsp-deferred) -#+END_SRC - -* Rust -#+BEGIN_SRC emacs-lisp - (use-package rust-mode - :mode "\\.rs\\'" - :general - (rust-mode-map "C-c " #'rust-format-buffer) - :config - (add-hook 'rust-mode-hook #'lsp-deferred)) - - - (use-package cargo - :after (rust-mode) - :config - (add-hook 'rust-mode-hook #'cargo-minor-mode)) -#+END_SRC - -* Elixir -#+BEGIN_SRC emacs-lisp - (use-package elixir-mode - :defer t) - - (use-package alchemist - :hook ((elixir-mode . alchemist-mode) - (alchemist-iex-mode . company-mode))) -#+END_SRC - -* XML -Set up hideshow for nXML mode: -#+BEGIN_SRC emacs-lisp - (add-hook 'nxml-mode-hook #'hs-minor-mode) - - (add-to-list 'hs-special-modes-alist - '(nxml-mode - "\\|]*[^/]>" ;; regexp for end block - "