]> crepu.dev Git - config.git/blob - djavu-asus/emacs/elpa/pyvenv-20211014.707/pyvenv.el
6c042861a751d75e2d0be6f4c27666d1d93fa93c
[config.git] / djavu-asus / emacs / elpa / pyvenv-20211014.707 / pyvenv.el
1 ;;; pyvenv.el --- Python virtual environment interface -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2013-2017 Jorgen Schaefer <contact@jorgenschaefer.de>
4
5 ;; Author: Jorgen Schaefer <contact@jorgenschaefer.de>
6 ;; URL: http://github.com/jorgenschaefer/pyvenv
7 ;; Version: 1.21
8 ;; Keywords: Python, Virtualenv, Tools
9
10 ;; This program is free software; you can redistribute it and/or
11 ;; modify it under the terms of the GNU General Public License
12 ;; as published by the Free Software Foundation; either version 3
13 ;; of the License, or (at your option) any later version.
14
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;; This is a simple global minor mode which will replicate the changes
26 ;; done by virtualenv activation inside Emacs.
27
28 ;; The main entry points are `pyvenv-activate', which queries the user
29 ;; for a virtual environment directory to activate, and
30 ;; `pyvenv-workon', which queries for a virtual environment in
31 ;; $WORKON_HOME (from virtualenvwrapper.sh).
32
33 ;; If you want your inferior Python processes to be restarted
34 ;; automatically when you switch your virtual environment, add
35 ;; `pyvenv-restart-python' to `pyvenv-post-activate-hooks'.
36
37 ;;; Code:
38
39 (require 'eshell)
40 (require 'json)
41 (require 'subr-x)
42
43 ;; User customization
44
45 (defgroup pyvenv nil
46 "Python Virtual Environment Interface."
47 :prefix "pyvenv-"
48 :group 'languages)
49
50 (defcustom pyvenv-workon nil
51 "The intended virtualenv in the virtualenvwrapper directory.
52
53 This is rarely useful to set globally. Rather, set this in file-
54 or directory-local variables using \\[add-file-local-variable] or
55 \\[add-dir-local-variable].
56
57 When `pyvenv-mode' is enabled, pyvenv will switch to this
58 virtualenv. If a virtualenv is already enabled, it will ask first."
59 :type 'pyvenv-workon
60 :safe #'stringp
61 :group 'pyvenv)
62
63 (defcustom pyvenv-activate nil
64 "The intended virtualenv directory.
65
66 This is rarely useful to set globally. Rather, set this in file-
67 or directory-local variables using \\[add-file-local-variable] or
68 \\[add-dir-local-variable].
69
70 When `pyvenv-mode' is enabled, pyvenv will switch to this
71 virtualenv. If a virtualenv is already enabled, it will ask first."
72 :type 'directory
73 :safe #'stringp
74 :group 'pyvenv)
75
76 (defcustom pyvenv-tracking-ask-before-change nil
77 "Non-nil means pyvenv will ask before automatically changing a virtualenv.
78
79 This can happen when a new file is opened with a buffer-local
80 value (from file-local or directory-local variables) for
81 `pyvenv-workon' or `pyvenv-workon', or if `pyvenv-tracking-mode'
82 is active, after every command."
83 :type 'boolean
84 :group 'pyvenv)
85
86 (defcustom pyvenv-virtualenvwrapper-python
87 (or (getenv "VIRTUALENVWRAPPER_PYTHON")
88 (executable-find "python3")
89 (executable-find "python")
90 (executable-find "py")
91 (executable-find "pythonw")
92 "python")
93 "The python process which has access to the virtualenvwrapper module.
94
95 This should be $VIRTUALENVWRAPPER_PYTHON outside of Emacs, but
96 virtualenvwrapper.sh does not export that variable. We make an
97 educated guess, but that can be off."
98 :type '(file :must-match t)
99 :safe #'file-directory-p
100 :group 'pyvenv)
101
102 (defcustom pyvenv-exec-shell
103 (or (executable-find "bash")
104 (executable-find "sh")
105 shell-file-name)
106 "The path to a POSIX compliant shell to use for running
107 virtualenv hooks. Useful if you use a non-POSIX shell (e.g.
108 fish)."
109 :type '(file :must-match t)
110 :group 'pyvenv)
111
112 (defcustom pyvenv-default-virtual-env-name nil
113 "Default directory to use when prompting for a virtualenv directory
114 in `pyvenv-activate'."
115 :type 'string
116 :group 'pyvenv)
117
118 ;; API for other libraries
119
120 (defvar pyvenv-virtual-env nil
121 "The current virtual environment.
122
123 Do not set this variable directly; use `pyvenv-activate' or
124 `pyvenv-workon'.")
125
126 (defvar pyvenv-virtual-env-path-directories nil
127 "Directories added to PATH by the current virtual environment.
128
129 Do not set this variable directly; use `pyvenv-activate' or
130 `pyvenv-workon'.")
131
132 (defvar pyvenv-virtual-env-name nil
133 "The name of the current virtual environment.
134
135 This is usually the base name of `pyvenv-virtual-env'.")
136
137
138 (defvar pyvenv-pre-create-hooks nil
139 "Hooks run before a virtual environment is created.")
140
141
142 (defvar pyvenv-post-create-hooks nil
143 "Hooks run after a virtual environment is created.")
144
145
146 (defvar pyvenv-pre-activate-hooks nil
147 "Hooks run before a virtual environment is activated.
148
149 `pyvenv-virtual-env' is already set.")
150
151 (defvar pyvenv-post-activate-hooks nil
152 "Hooks run after a virtual environment is activated.
153
154 `pyvenv-virtual-env' is set.")
155
156 (defvar pyvenv-pre-deactivate-hooks nil
157 "Hooks run before a virtual environment is deactivated.
158
159 `pyvenv-virtual-env' is set.")
160
161 (defvar pyvenv-post-deactivate-hooks nil
162 "Hooks run after a virtual environment is deactivated.
163
164 `pyvenv-virtual-env' is still set.")
165
166 (defvar pyvenv-mode-line-indicator '(pyvenv-virtual-env-name
167 ("[" pyvenv-virtual-env-name "] "))
168 "How `pyvenv-mode' will indicate the current environment in the mode line.")
169
170 ;; Internal code.
171
172 (defvar pyvenv-old-process-environment nil
173 "The old process environment that needs to be restored after deactivating the current environment.")
174
175
176 (defun pyvenv-create (venv-name python-executable)
177 "Create virtualenv. VENV-NAME PYTHON-EXECUTABLE."
178 (interactive (list
179 (read-from-minibuffer "Name of virtual environment: ")
180 (let ((dir (if pyvenv-virtualenvwrapper-python
181 (file-name-directory pyvenv-virtualenvwrapper-python)
182 nil))
183 (initial (if pyvenv-virtualenvwrapper-python
184 (file-name-base pyvenv-virtualenvwrapper-python)
185 nil)))
186 (read-file-name "Python interpreter to use: " dir nil nil initial))))
187 (let ((venv-dir (concat (file-name-as-directory (pyvenv-workon-home))
188 venv-name)))
189 (unless (file-exists-p venv-dir)
190 (run-hooks 'pyvenv-pre-create-hooks)
191 (cond
192 ((executable-find "virtualenv")
193 (with-current-buffer (generate-new-buffer "*virtualenv*")
194 (call-process "virtualenv" nil t t
195 "-p" python-executable venv-dir)
196 (display-buffer (current-buffer))))
197 ((= 0 (call-process python-executable nil nil nil
198 "-m" "venv" "-h"))
199 (with-current-buffer (generate-new-buffer "*venv*")
200 (call-process python-executable nil t t
201 "-m" "venv" venv-dir)
202 (display-buffer (current-buffer))))
203 (t
204 (error "Pyvenv necessitates the 'virtualenv' python package")))
205 (run-hooks 'pyvenv-post-create-hooks))
206 (pyvenv-activate venv-dir)))
207
208
209 ;;;###autoload
210 (defun pyvenv-activate (directory)
211 "Activate the virtual environment in DIRECTORY."
212 (interactive (list (read-directory-name "Activate venv: " nil nil nil
213 pyvenv-default-virtual-env-name)))
214 (setq directory (expand-file-name directory))
215 (pyvenv-deactivate)
216 (setq pyvenv-virtual-env (file-name-as-directory directory)
217 pyvenv-virtual-env-name (file-name-nondirectory
218 (directory-file-name directory))
219 python-shell-virtualenv-path directory
220 python-shell-virtualenv-root directory)
221 ;; Set venv name as parent directory for generic directories or for
222 ;; the user's default venv name
223 (when (or (member pyvenv-virtual-env-name '("venv" ".venv" "env" ".env"))
224 (and pyvenv-default-virtual-env-name
225 (string= pyvenv-default-virtual-env-name
226 pyvenv-virtual-env-name)))
227 (setq pyvenv-virtual-env-name
228 (file-name-nondirectory
229 (directory-file-name
230 (file-name-directory
231 (directory-file-name directory))))))
232 (pyvenv-run-virtualenvwrapper-hook "pre_activate" nil pyvenv-virtual-env)
233 (run-hooks 'pyvenv-pre-activate-hooks)
234 (setq pyvenv-virtual-env-path-directories (pyvenv--virtual-env-bin-dirs directory)
235 ;; Variables that must be reset during deactivation.
236 pyvenv-old-process-environment (list (cons "PYTHONHOME" (getenv "PYTHONHOME"))
237 (cons "VIRTUAL_ENV" nil)))
238 (setenv "VIRTUAL_ENV" directory)
239 (setenv "PYTHONHOME" nil)
240 (pyvenv--add-dirs-to-PATH pyvenv-virtual-env-path-directories)
241 (pyvenv-run-virtualenvwrapper-hook "post_activate" 'propagate-env)
242 (run-hooks 'pyvenv-post-activate-hooks))
243
244 ;;;###autoload
245 (defun pyvenv-deactivate ()
246 "Deactivate any current virtual environment."
247 (interactive)
248 (when pyvenv-virtual-env
249 (pyvenv-run-virtualenvwrapper-hook "pre_deactivate" 'propagate-env)
250 (run-hooks 'pyvenv-pre-deactivate-hooks)
251 (pyvenv--remove-dirs-from-PATH (pyvenv--virtual-env-bin-dirs pyvenv-virtual-env))
252 (dolist (envvar pyvenv-old-process-environment)
253 (setenv (car envvar) (cdr envvar)))
254 ;; Make sure PROPAGATE-ENV is nil here, so that it does not change
255 ;; `exec-path', as $PATH is different
256 (pyvenv-run-virtualenvwrapper-hook "post_deactivate"
257 nil
258 pyvenv-virtual-env)
259 (run-hooks 'pyvenv-post-deactivate-hooks))
260 (setq pyvenv-virtual-env nil
261 pyvenv-virtual-env-path-directories nil
262 pyvenv-virtual-env-name nil
263 python-shell-virtualenv-root nil
264 python-shell-virtualenv-path nil))
265
266 (defvar pyvenv-workon-history nil
267 "Prompt history for `pyvenv-workon'.")
268
269 ;;;###autoload
270 (defun pyvenv-workon (name)
271 "Activate a virtual environment from $WORKON_HOME.
272
273 If the virtual environment NAME is already active, this function
274 does not try to reactivate the environment."
275 (interactive
276 (list
277 (completing-read "Work on: " (pyvenv-virtualenv-list)
278 nil t nil 'pyvenv-workon-history nil nil)))
279 (unless (member name (list "" nil pyvenv-virtual-env-name))
280 (pyvenv-activate (format "%s/%s"
281 (pyvenv-workon-home)
282 name))))
283
284 (defun pyvenv-virtualenv-list (&optional noerror)
285 "Prompt the user for a name in $WORKON_HOME.
286
287 If NOERROR is set, do not raise an error if WORKON_HOME is not
288 configured."
289 (let ((workon-home (pyvenv-workon-home))
290 (result nil))
291 (if (not (file-directory-p workon-home))
292 (when (not noerror)
293 (error "Can't find a workon home directory, set $WORKON_HOME"))
294 (dolist (name (directory-files workon-home))
295 (when (or (file-exists-p (format "%s/%s/bin/activate"
296 workon-home name))
297 (file-exists-p (format "%s/%s/bin/python"
298 workon-home name))
299 (file-exists-p (format "%s/%s/Scripts/activate.bat"
300 workon-home name))
301 (file-exists-p (format "%s/%s/python.exe"
302 workon-home name)))
303 (setq result (cons name result))))
304 (sort result (lambda (a b)
305 (string-lessp (downcase a)
306 (downcase b)))))))
307
308 (define-widget 'pyvenv-workon 'choice
309 "Select an available virtualenv from virtualenvwrapper."
310 :convert-widget
311 (lambda (widget)
312 (setq widget (widget-copy widget))
313 (widget-put widget
314 :args (cons '(const :tag "None" nil)
315 (mapcar (lambda (env)
316 (list 'const env))
317 (pyvenv-virtualenv-list t))))
318 (widget-types-convert-widget widget))
319
320 :prompt-value (lambda (_widget prompt _value _unbound)
321 (let ((name (completing-read
322 prompt
323 (cons "None"
324 (pyvenv-virtualenv-list t))
325 nil t)))
326 (if (equal name "None")
327 nil
328 name))))
329
330 (defvar pyvenv-mode-map (make-sparse-keymap)
331 "The mode keymap for `pyvenv-mode'.")
332
333 (easy-menu-define pyvenv-menu pyvenv-mode-map
334 "Pyvenv Menu"
335 '("Virtual Envs"
336 :visible pyvenv-mode
337 ("Workon"
338 :help "Activate a virtualenvwrapper environment"
339 :filter (lambda (&optional ignored)
340 (mapcar (lambda (venv)
341 (vector venv `(pyvenv-workon ,venv)
342 :style 'radio
343 :selected `(equal pyvenv-virtual-env-name
344 ,venv)))
345 (pyvenv-virtualenv-list t))))
346 ["Activate" pyvenv-activate
347 :help "Activate a virtual environment by directory"]
348 ["Deactivate" pyvenv-deactivate
349 :help "Deactivate the current virtual environment"
350 :active pyvenv-virtual-env
351 :suffix pyvenv-virtual-env-name]
352 ["Restart Python Processes" pyvenv-restart-python
353 :help "Restart all Python processes to use the current environment"]))
354
355 ;;;###autoload
356 (define-minor-mode pyvenv-mode
357 "Global minor mode for pyvenv.
358
359 Will show the current virtualenv in the mode line, and respect a
360 `pyvenv-workon' setting in files."
361 :global t
362 (cond
363 (pyvenv-mode
364 (add-to-list 'mode-line-misc-info '(pyvenv-mode pyvenv-mode-line-indicator))
365 (add-hook 'hack-local-variables-hook #'pyvenv-track-virtualenv))
366 ((not pyvenv-mode)
367 (setq mode-line-misc-info (delete '(pyvenv-mode pyvenv-mode-line-indicator)
368 mode-line-misc-info))
369 (remove-hook 'hack-local-variables-hook #'pyvenv-track-virtualenv))))
370
371 ;;;###autoload
372 (define-minor-mode pyvenv-tracking-mode
373 "Global minor mode to track the current virtualenv.
374
375 When this mode is active, pyvenv will activate a buffer-specific
376 virtualenv whenever the user switches to a buffer with a
377 buffer-local `pyvenv-workon' or `pyvenv-activate' variable."
378 :global t
379 (if pyvenv-tracking-mode
380 (add-hook 'post-command-hook 'pyvenv-track-virtualenv)
381 (remove-hook 'post-command-hook 'pyvenv-track-virtualenv)))
382
383 (defun pyvenv-track-virtualenv ()
384 "Set a virtualenv as specified for the current buffer.
385
386 If either `pyvenv-activate' or `pyvenv-workon' are specified, and
387 they specify a virtualenv different from the current one, switch
388 to that virtualenv."
389 (cond
390 (pyvenv-activate
391 (when (and (not (equal (file-name-as-directory pyvenv-activate)
392 pyvenv-virtual-env))
393 (or (not pyvenv-tracking-ask-before-change)
394 (y-or-n-p (format "Switch to virtualenv %s (currently %s)"
395 pyvenv-activate pyvenv-virtual-env))))
396 (pyvenv-activate pyvenv-activate)))
397 (pyvenv-workon
398 (when (and (not (equal pyvenv-workon pyvenv-virtual-env-name))
399 (or (not pyvenv-tracking-ask-before-change)
400 (y-or-n-p (format "Switch to virtualenv %s (currently %s)"
401 pyvenv-workon pyvenv-virtual-env-name))))
402 (pyvenv-workon pyvenv-workon)))))
403
404 (defun pyvenv-run-virtualenvwrapper-hook (hook &optional propagate-env &rest args)
405 "Run a virtualenvwrapper hook, and update the environment.
406
407 This will run a virtualenvwrapper hook and update the local
408 environment accordingly.
409
410 CAREFUL! If PROPAGATE-ENV is non-nil, this will modify your
411 `process-environment' and `exec-path'."
412 (when (pyvenv-virtualenvwrapper-supported)
413 (with-temp-buffer
414 (let ((tmpfile (make-temp-file "pyvenv-virtualenvwrapper-"))
415 (shell-file-name pyvenv-exec-shell))
416 (unwind-protect
417 (let ((default-directory (pyvenv-workon-home)))
418 (apply #'call-process
419 pyvenv-virtualenvwrapper-python
420 nil t nil
421 "-m" "virtualenvwrapper.hook_loader"
422 "--script" tmpfile
423 (if (getenv "HOOK_VERBOSE_OPTION")
424 (cons (getenv "HOOK_VERBOSE_OPTION")
425 (cons hook args))
426 (cons hook args)))
427 (call-process-shell-command
428 (mapconcat 'identity
429 (list
430 (format "%s -c 'import os, json; print(json.dumps(dict(os.environ)))'"
431 pyvenv-virtualenvwrapper-python)
432 (format ". '%s'" tmpfile)
433 (format
434 "%s -c 'import os, json; print(\"\\n=-=-=\"); print(json.dumps(dict(os.environ)))'"
435 pyvenv-virtualenvwrapper-python))
436 "; ")
437 nil t nil))
438 (delete-file tmpfile)))
439 (goto-char (point-min))
440 (when (not (re-search-forward "No module named '?virtualenvwrapper'?" nil t))
441 (let* ((json-key-type 'string)
442 (env-before (json-read))
443 (hook-output-start-pos (point))
444 (hook-output-end-pos (when (re-search-forward "\n=-=-=\n" nil t)
445 (match-beginning 0)))
446 (env-after (when hook-output-end-pos (json-read))))
447 (when hook-output-end-pos
448 (let ((output (string-trim (buffer-substring hook-output-start-pos
449 hook-output-end-pos))))
450 (when (> (length output) 0)
451 (with-help-window "*Virtualenvwrapper Hook Output*"
452 (with-current-buffer "*Virtualenvwrapper Hook Output*"
453 (let ((inhibit-read-only t))
454 (erase-buffer)
455 (insert
456 (format
457 "Output from the virtualenvwrapper hook %s:\n\n"
458 hook)
459 output))))))
460 (when propagate-env
461 (dolist (binding (pyvenv--env-diff (sort env-before (lambda (x y) (string-lessp (car x) (car y))))
462 (sort env-after (lambda (x y) (string-lessp (car x) (car y))))))
463 (setenv (car binding) (cdr binding))
464 (when (eq (car binding) 'PATH)
465 (let ((new-path-elts (split-string (cdr binding)
466 path-separator)))
467 (setq exec-path new-path-elts)
468 (setq-default eshell-path-env new-path-elts)))))))))))
469
470
471 (defun pyvenv--env-diff (env-before env-after)
472 "Calculate diff between ENV-BEFORE alist and ENV-AFTER alist.
473
474 Both ENV-BEFORE and ENV-AFTER must be sorted alists of (STR . STR)."
475 (let (env-diff)
476 (while (or env-before env-after)
477 (cond
478 ;; K-V are the same, both proceed to the next one.
479 ((equal (car-safe env-before) (car-safe env-after))
480 (setq env-before (cdr env-before)
481 env-after (cdr env-after)))
482
483 ;; env-after is missing one element: add (K-before . nil) to diff
484 ((and env-before (or (null env-after) (string-lessp (caar env-before)
485 (caar env-after))))
486 (setq env-diff (cons (cons (caar env-before) nil) env-diff)
487 env-before (cdr env-before)))
488 ;; Otherwise: add env-after element to the diff, progress env-after,
489 ;; progress env-before only if keys matched.
490 (t
491 (setq env-diff (cons (car env-after) env-diff))
492 (when (equal (caar env-after) (caar env-before))
493 (setq env-before (cdr env-before)))
494 (setq env-after (cdr env-after)))))
495 (nreverse env-diff)))
496
497
498 ;;;###autoload
499 (defun pyvenv-restart-python ()
500 "Restart Python inferior processes."
501 (interactive)
502 (dolist (buf (buffer-list))
503 (with-current-buffer buf
504 (when (and (eq major-mode 'inferior-python-mode)
505 (get-buffer-process buf))
506 (let ((cmd (combine-and-quote-strings (process-command
507 (get-buffer-process buf))))
508 (dedicated (if (string-match "\\[.*\\]$" (buffer-name buf))
509 t
510 nil))
511 (show nil))
512 (delete-process (get-buffer-process buf))
513 (goto-char (point-max))
514 (insert "\n\n"
515 "###\n"
516 (format "### Restarting in virtualenv %s (%s)\n"
517 pyvenv-virtual-env-name pyvenv-virtual-env)
518 "###\n"
519 "\n\n")
520 (run-python cmd dedicated show)
521 (goto-char (point-max)))))))
522
523 (defun pyvenv-hook-dir ()
524 "Return the current hook directory.
525
526 This is usually the value of $VIRTUALENVWRAPPER_HOOK_DIR, but
527 virtualenvwrapper has stopped exporting that variable, so we go
528 back to the default of $WORKON_HOME or even just ~/.virtualenvs/."
529 (or (getenv "VIRTUALENVWRAPPER_HOOK_DIR")
530 (pyvenv-workon-home)))
531
532 (defun pyvenv-workon-home ()
533 "Return the current workon home.
534
535 This is the value of $WORKON_HOME or ~/.virtualenvs."
536 (or (getenv "WORKON_HOME")
537 (expand-file-name "~/.virtualenvs")))
538
539 (defun pyvenv-virtualenvwrapper-supported ()
540 "Return true iff virtualenvwrapper is supported.
541
542 Right now, this just checks if WORKON_HOME is set."
543 (getenv "WORKON_HOME"))
544
545 (defun pyvenv--virtual-env-bin-dirs (virtual-env)
546 (let ((virtual-env
547 (if (string= "/" (directory-file-name virtual-env))
548 ""
549 (directory-file-name virtual-env))))
550 (append
551 ;; Unix
552 (when (file-exists-p (format "%s/bin" virtual-env))
553 (list (format "%s/bin" virtual-env)))
554 ;; Windows
555 (when (file-exists-p (format "%s/Scripts" virtual-env))
556 (list (format "%s/Scripts" virtual-env)
557 ;; Apparently, some virtualenv
558 ;; versions on windows put the
559 ;; python.exe in the virtualenv root
560 ;; for some reason?
561 virtual-env)))))
562
563 (defun pyvenv--replace-once-destructive (list oldvalue newvalue)
564 "Replace one element equal to OLDVALUE with NEWVALUE values in LIST."
565 (let ((cur-elt list))
566 (while (and cur-elt (not (equal oldvalue (car cur-elt))))
567 (setq cur-elt (cdr cur-elt)))
568 (when cur-elt (setcar cur-elt newvalue))))
569
570 (defun pyvenv--remove-many-once (values-to-remove list)
571 "Return a copy of LIST with each element from VALUES-TO-REMOVE removed once."
572 ;; Non-interned symbol is not eq to anything but itself.
573 (let ((values-to-remove (copy-sequence values-to-remove))
574 (sentinel (make-symbol "sentinel")))
575 (delq sentinel
576 (mapcar (lambda (x)
577 (if (pyvenv--replace-once-destructive values-to-remove x sentinel)
578 sentinel
579 x))
580 list))))
581
582 (defun pyvenv--prepend-to-pathsep-string (values-to-prepend str)
583 "Prepend values from VALUES-TO-PREPEND list to path-delimited STR."
584 (mapconcat 'identity
585 (append values-to-prepend (split-string str path-separator))
586 path-separator))
587
588 (defun pyvenv--remove-from-pathsep-string (values-to-remove str)
589 "Remove all values from VALUES-TO-REMOVE list from path-delimited STR."
590 (mapconcat 'identity
591 (pyvenv--remove-many-once values-to-remove (split-string str path-separator))
592 path-separator))
593
594 (defun pyvenv--add-dirs-to-PATH (dirs-to-add)
595 "Add DIRS-TO-ADD to different variables related to execution paths."
596 (let* ((new-eshell-path-env (pyvenv--prepend-to-pathsep-string dirs-to-add (default-value 'eshell-path-env)))
597 (new-path-envvar (pyvenv--prepend-to-pathsep-string dirs-to-add (getenv "PATH"))))
598 (setq exec-path (append dirs-to-add exec-path))
599 (setq-default eshell-path-env new-eshell-path-env)
600 (setenv "PATH" new-path-envvar)))
601
602 (defun pyvenv--remove-dirs-from-PATH (dirs-to-remove)
603 "Remove DIRS-TO-REMOVE from different variables related to execution paths."
604 (let* ((new-eshell-path-env (pyvenv--remove-from-pathsep-string dirs-to-remove (default-value 'eshell-path-env)))
605 (new-path-envvar (pyvenv--remove-from-pathsep-string dirs-to-remove (getenv "PATH"))))
606 (setq exec-path (pyvenv--remove-many-once dirs-to-remove exec-path))
607 (setq-default eshell-path-env new-eshell-path-env)
608 (setenv "PATH" new-path-envvar)))
609
610 ;;; Compatibility
611
612 (when (not (fboundp 'file-name-base))
613 ;; Emacs 24.3
614 (defun file-name-base (&optional filename)
615 "Return the base name of the FILENAME: no directory, no extension.
616 FILENAME defaults to `buffer-file-name'."
617 (file-name-sans-extension
618 (file-name-nondirectory (or filename (buffer-file-name)))))
619 )
620
621 (when (not (boundp 'mode-line-misc-info))
622 (defvar mode-line-misc-info nil
623 "Compatibility variable for 24.3+")
624 (let ((line mode-line-format))
625 (while line
626 (when (eq 'which-func-mode
627 (car-safe (car-safe (cdr line))))
628 (setcdr line (cons 'mode-line-misc-format
629 (cdr line)))
630 (setq line (cdr line)))
631 (setq line (cdr line)))))
632
633 (provide 'pyvenv)
634 ;;; pyvenv.el ends here