Browse Source

[emacs] Add django-run-tests support

Colin Powell 3 days ago
parent
commit
ec2a7a0efd
2 changed files with 79 additions and 0 deletions
  1. 70 0
      emacs/.config/doom/+django-tests.el
  2. 9 0
      emacs/.config/doom/config.el

+ 70 - 0
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)

+ 9 - 0
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