From: rearman Date: Fri, 28 Jun 2024 21:11:31 +0000 (-0400) Subject: Auto-Balance parens with ']' in REPLs X-Git-Url: https://git.earman.xyz/?a=commitdiff_plain;h=72279858321fa33a69c8792bef250a2a9c5b2ab4;p=emacsinit.git Auto-Balance parens with ']' in REPLs --- diff --git a/re/re-bindings.el b/re/re-bindings.el index cf1b137..1dd9b12 100644 --- a/re/re-bindings.el +++ b/re/re-bindings.el @@ -65,6 +65,20 @@ (keymap-global-set "C-M-S-q" (lambda () (interactive) (indent-pp-sexp t))) +(defvar *re/lisp-mode-hooks* + '(emacs-lisp-mode-hook + lisp-mode-hook + slime-mode-hook + scheme-mode-hook)) + +(dolist (hook *re/lisp-mode-hooks*) + (add-hook hook + (lambda () + (keymap-set lisp-mode-shared-map "]" (re/balance-and-eval-sexp #'newline))))) + +(add-hook 'lisp-interaction-mode-hook + (lambda () + (keymap-set lisp-interaction-mode-map "]" (re/balance-and-eval-sexp #'eval-print-last-sexp)))) ;; IELM (keymap-global-set "C-c i" #'ielm) @@ -72,7 +86,7 @@ (lambda () (keymap-set inferior-emacs-lisp-mode-map "C-l" #'comint-clear-buffer) (keymap-set inferior-emacs-lisp-mode-map ")" (re/send-on-close-paren #'ielm-send-input)) - (keymap-set inferior-emacs-lisp-mode-map "]" #'re/insert-all-parens))) + (keymap-set inferior-emacs-lisp-mode-map "]" (re/balance-and-eval-sexp #'ielm-send-input)))) ;; Eshell (keymap-global-set "C-c e" #'eshell) @@ -80,13 +94,13 @@ (lambda () (keymap-set eshell-mode-map "C-d" #'eshell-quit-or-delete-char) (keymap-set eshell-mode-map ")" (re/send-on-close-paren #'eshell-send-input)) - (keymap-set eshell-mode-map "]" #'re/insert-all-parens))) + (keymap-set eshell-mode-map "]" (re/balance-and-eval-sexp #'eshell-send-input)))) ;; SLIME REPL (add-hook 'slime-repl-mode-hook (lambda () (keymap-set slime-repl-mode-map ")" (re/send-on-close-paren #'slime-repl-return)) - (keymap-set slime-repl-mode-map "]" #'re/insert-all-parens))) + (keymap-set slime-repl-mode-map "]" (re/balance-and-eval-sexp #'slime-repl-return)))) ;; Org Starters (keymap-global-set "C-c l" #'org-store-link) diff --git a/re/re-repl-defuns.el b/re/re-repl-defuns.el index 30c6e40..5d3aae3 100644 --- a/re/re-repl-defuns.el +++ b/re/re-repl-defuns.el @@ -6,21 +6,44 @@ ;; Any Lisp Repl (defmacro re/send-on-close-paren (executor) "Generalizes sending an execute on close paren. -When a sexp is complete - that is when parens balance as you type - execute it. -Use this macro as a direct binding" + Interactively call `executor'. For `executor', use whatever + function is called by `' in the applicable REPL. For a + non-repl, use `newline' or similar." + `(lambda (&optional arg) + (interactive "p") + (insert-char 41 arg) + (call-interactively ,executor))) + +(defun re/sexp-drop-paren-p () + "Returns t if sexp needs fewer parens to balance." + (<0 (car (syntax-ppss)))) + +(defun re/sexp-need-paren-p () + "Returns t if sexp needs more parens to balance." + (>0 (car (syntax-ppss)))) + +(defun re/sexp-unbalanced-count () + "Returns distance from balanced sexp." + (abs (car (syntax-ppss)))) + +(defun re/balance-sexp () + "Balance the sexp before point. +Either delete or add as many ')' as needed." + (let ((distance (re/sexp-unbalanced-count))) + (cond + ((re/sexp-need-paren-p) (insert-char 41 distance)) + ((re/sexp-drop-paren-p) (backward-delete-char distance))))) + +(defmacro re/balance-and-eval-sexp (executor) + "Balance the sexp before point, then call `executor'. +Call `re/balance-sexp', then interactively call `executor'. Bind +this to ']' for the interlisp experience. For `executor', use +whatever function is called by `' in the applicable REPL. +For a non-repl, use `newline' or similar." `(lambda () (interactive) - (insert-char 41) - (when (= 0 (car (syntax-ppss))) - (call-interactively ,executor)))) - -(defun re/insert-all-parens () - "Inserts all the parens needed to balance a sexp. -If multiple parens are needed at the end to balance a sexp, insert them. -Bind this to ']' for the interlisp experience." - (interactive) - (while (>0 (car (syntax-ppss))) - (insert-char 41))) + (re/balance-sexp) + (call-interactively ,executor))) ;; Eshell (defun eshell-quit-or-delete-char (arg)