Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.5 KiB

  1. (defun rlbr/get-venv-name (&optional library-root)
  2. "Generate venv name based off of the base-name of the library root"
  3. (file-name-base
  4. (directory-file-name
  5. (if library-root
  6. library-root
  7. (elpy-library-root)))))
  8. (defun rlbr/handle-name-conflicts (venv-name)
  9. "Deal with potential name conflicts in venv"
  10. (let ((venv-conflicts)
  11. (venv-partition-name))
  12. (setq venv-partition-name (rlbr/split-venv-with-number venv-name))
  13. (setq venv-conflicts
  14. (seq-filter
  15. (lambda (item) (string-equal (cdr item) venv-name))
  16. (mapcar #'rlbr/split-venv-with-number (pyvenv-virtualenv-list))))
  17. (when venv-conflicts
  18. (setcar venv-partition-name (1+ (apply 'max (mapcar #'car venv-conflicts)))))
  19. (rlbr/join-venv-with-number venv-partition-name)))
  20. ;; We'll save using file-precious-flag, so avoid destroying
  21. ;; symlinks. (If we're not already visiting the buffer, this is
  22. ;; handled by find-file-visit-truename, above.)
  23. (defun rlbr/save-buffer-func-to-file (visit-file func args)
  24. "Rip off of custom-save-all"
  25. (let* ((filename visit-file)
  26. (recentf-exclude (if recentf-mode
  27. (append
  28. `(,(concat "\\`" (regexp-quote (recentf-expand-file-name visit-file)) "\\'")
  29. ,(concat "\\`" (regexp-quote (file-truename (recentf-expand-file-name visit-file))) "\\'"))
  30. recentf-exclude)))
  31. (old-buffer (find-buffer-visiting filename))
  32. old-buffer-name)
  33. (with-current-buffer
  34. (let ((find-file-visit-truename t))
  35. (or old-buffer
  36. (let ((delay-mode-hooks t))
  37. (find-file-noselect filename))))
  38. (when old-buffer
  39. (setq old-buffer-name
  40. (buffer-file-name))
  41. (set-visited-file-name
  42. (file-chase-links filename)))
  43. (unless (eq major-mode
  44. 'emacs-lisp-mode)
  45. (delay-mode-hooks
  46. (emacs-lisp-mode)))
  47. (let ((inhibit-read-only t)
  48. (print-length nil)
  49. (print-level nil))
  50. (apply func args))
  51. (let ((file-precious-flag t))
  52. (save-buffer))
  53. (if old-buffer
  54. (progn
  55. (set-visited-file-name
  56. old-buffer-name)
  57. (set-buffer-modified-p nil))
  58. (kill-buffer (current-buffer))))))
  59. (defun rlbr/setup-python-venv-dirlocals (&optional library-root)
  60. "Setup .dir-locals file in library root and tell vc system to ignore .dir-locals file"
  61. (let* ((library-root (if library-root
  62. library-root
  63. (elpy-library-root)))
  64. (default-directory library-root)
  65. (dir-locals-path (expand-file-name
  66. ".dir-locals.el"))
  67. (venv-name (rlbr/get-venv-name
  68. library-root)))
  69. (rlbr/save-buffer-func-to-file dir-locals-path 'add-dir-local-variable
  70. `(python-mode pyvenv-workon ,venv-name))
  71. (let* ((vc-root (vc-find-root dir-locals-path ".git"))
  72. (vc-ignore-file (vc-call-backend 'Git 'find-ignore-file vc-root)))
  73. (if (apply 'string-equal (mapcar 'directory-file-name (mapcar 'file-truename (list vc-root library-root))))
  74. (progn
  75. (unless (file-exists-p vc-ignore-file)
  76. (with-temp-buffer
  77. (write-file vc-ignore-file)))
  78. (vc-ignore ".dir-locals.el"))
  79. (when (y-or-n-p (format "Ignore .dir-locals.el in repo '%s' ?" vc-root))
  80. (unless (file-exists-p vc-ignore-file)
  81. (with-temp-buffer
  82. (write-file vc-ignore-file)))
  83. (vc-ignore ".dir-locals.el"))))))
  84. (defun rlbr/init-python-venv-in-library-root (&optional library-root)
  85. "If no venv is specified in the library root .dir-locals file, prompt to either create one or use default"
  86. (let ((venv-name (rlbr/get-venv-name)))
  87. (setq venv-name (rlbr/handle-name-conflicts venv-name))
  88. (if (y-or-n-p (format "Create venv '%'?" venv-name))
  89. (pyvenv-create venv-name python-command))))