From ec2a7a0efdf2f736d7283f2ccf5a592f85e63fac Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Thu, 8 Jan 2026 15:40:44 -0500 Subject: [PATCH] [emacs] Add django-run-tests support --- emacs/.config/doom/+django-tests.el | 70 +++++++++++++++++++++++++++++ emacs/.config/doom/config.el | 9 ++++ 2 files changed, 79 insertions(+) create mode 100644 emacs/.config/doom/+django-tests.el diff --git a/emacs/.config/doom/+django-tests.el b/emacs/.config/doom/+django-tests.el new file mode 100644 index 0000000..dbd3cbb --- /dev/null +++ b/emacs/.config/doom/+django-tests.el @@ -0,0 +1,70 @@ +;;; +django-tests.el -*- lexical-binding: t; -*- + +(require 'projectile) +(require 'python) +(require 'subr-x) + +(defun django--project-root () + (or (projectile-project-root) + (user-error "Not in a Projectile project"))) + +(defun django--module-from-file (file root) + (let* ((rel (file-relative-name file root)) + (no-ext (file-name-sans-extension rel))) + (replace-regexp-in-string "/" "." no-ext))) + +(defun django--def-name-at-point () + (save-excursion + (when (ignore-errors (python-nav-beginning-of-defun) t) + (when (looking-at (rx bol (* space) "def" (+ space) + (group (+ (or word ?_))) (* space) "(")) + (match-string-no-properties 1))))) + +(defun django--enclosing-class-name () + (save-excursion + (let ((found nil) + (limit (point-min))) + (while (and (not found) (> (point) limit)) + (python-nav-beginning-of-statement) + (when (looking-at (rx bol (* space) "class" (+ space) + (group (+ (or word ?_))))) + (setq found (match-string-no-properties 1))) + (condition-case _err + (python-nav-backward-block) + (error (goto-char limit)))) + found))) + +(defun django--selector-at-point () + (let ((fn (django--def-name-at-point)) + (cls (django--enclosing-class-name))) + (cond + ((and fn (string-prefix-p "test_" fn)) + (if cls (format "%s.%s" cls fn) fn)) + (cls cls) + (t nil)))) + +(defun django-run-tests (&optional module selector) + (interactive) + (let* ((module-part (or module "")) + (selector-part (if selector (concat "." selector) "")) + (param (string-trim (concat module-part selector-part))) + (command (format "python manage.py test %s" param))) + (message "Running command: %s" command) + (projectile-run-async-shell-command-in-root command "*Django tests*"))) + +(defun django-run-test-at-point () + (interactive) + (let* ((root (django--project-root)) + (file (or (buffer-file-name) (user-error "Buffer is not visiting a file"))) + (module (django--module-from-file file root)) + (sel (django--selector-at-point))) + (django-run-tests module sel))) + +(defun django-run-tests-for-current-file () + (interactive) + (let* ((root (django--project-root)) + (file (or (buffer-file-name) (user-error "Buffer is not visiting a file"))) + (module (django--module-from-file file root))) + (django-run-tests module nil))) + +(provide '+django-tests) diff --git a/emacs/.config/doom/config.el b/emacs/.config/doom/config.el index a6a76f1..b69826f 100644 --- a/emacs/.config/doom/config.el +++ b/emacs/.config/doom/config.el @@ -25,6 +25,15 @@ (advice-add 'org-agenda :before #'vulpea-agenda-files-update) (advice-add 'org-todo-list :before #'vulpea-agenda-files-update) +(load! "+django-tests") +(map! :after python + :map python-mode-map + :localleader + (:prefix ("t" . "tests") + :desc "django test at point" "d" #'django-run-test-at-point + :desc "django tests for file" "f" #'django-run-tests-for-current-file + :desc "django all tests" "a" (cmd! (django-run-tests "" nil)))) + (setq +format-on-save-disabled-modes (add-to-list '+format-on-save-disabled-modes 'typescript-mode)) (map! ;; Easier window movement