mirror of
https://github.com/SqrtMinusOne/micromamba.el.git
synced 2025-12-10 13:23:02 +03:00
Initial commit
This commit is contained in:
commit
1997a345e2
2 changed files with 217 additions and 0 deletions
0
README.org
Normal file
0
README.org
Normal file
217
micromamba.el
Normal file
217
micromamba.el
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
;;; micromamba.el --- A simple micromamba integration for Emacs -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 Korytov Pavel
|
||||
|
||||
;; Author: Korytov Pavel <thexcloud@gmail.com>
|
||||
;; Maintainer: Korytov Pavel <thexcloud@gmail.com>
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "27.1") (pythonic "0.1.0"))
|
||||
;; Homepage: https://github.com/SqrtMinusOne/micromamba.el
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Use conda.el for full mamba.
|
||||
|
||||
;;; Code:
|
||||
(require 'json)
|
||||
(require 'pythonic)
|
||||
(require 'seq)
|
||||
|
||||
(defgroup micromamba nil
|
||||
"Micromamba (environment manager) integration for Emacs."
|
||||
:group 'python)
|
||||
|
||||
(defcustom micromamba-home "~/micromamba"
|
||||
"Location of micromamba home evironment directory."
|
||||
:type 'string
|
||||
:group 'micromamba)
|
||||
|
||||
(defcustom micromamba-executable (executable-find "micromamba")
|
||||
"Path to micromamba executable."
|
||||
:type 'string
|
||||
:group 'micromamba)
|
||||
|
||||
(defcustom micromamba-preactivate-hook nil
|
||||
"Hook run before a micromamba environment is activated."
|
||||
:type 'hook
|
||||
:group 'micromamba)
|
||||
|
||||
(defcustom micromamba-postactivate-hook nil
|
||||
"Hook run after a micromamba environment is activated."
|
||||
:type 'hook
|
||||
:group 'micromamba)
|
||||
|
||||
(defcustom micromamba-predeactivate-hook nil
|
||||
"Hook run before a micromamba environment is deactivated."
|
||||
:type 'hook
|
||||
:group 'micromamba)
|
||||
|
||||
(defcustom micromamba-postdeactivate-hook nil
|
||||
"Hook run after a micromamba environment is deactivated."
|
||||
:type 'hook
|
||||
:group 'micromamba)
|
||||
|
||||
(defvar micromamba-env-current-prefix nil
|
||||
"Current activated micromamba environment.")
|
||||
|
||||
(defun micromamba--call-json (&rest args)
|
||||
"Call micromamba and parse the return value as JSON.
|
||||
|
||||
Pass ARGS as arguments to the program."
|
||||
(unless micromamba-executable
|
||||
(user-error "Micromamba-executable is not set!"))
|
||||
(with-temp-buffer
|
||||
(apply #'call-process micromamba-executable nil t nil args)
|
||||
(goto-char (point-min))
|
||||
(json-read)))
|
||||
|
||||
(defun micromamba-envs ()
|
||||
"Get micromamba environments.
|
||||
|
||||
Returns an alist with environments, where the key is the name and the
|
||||
value is the prefix. Duplicate names are replaced with prefixes."
|
||||
(let* ((envs
|
||||
(append (alist-get 'envs (micromamba--call-json "env" "list" "--json")) nil))
|
||||
(base-env (alist-get 'base\ environment
|
||||
(micromamba--call-json "info" "--json")))
|
||||
;; I have some environments from conda with the same name :-(
|
||||
(dupe-name-map (make-hash-table :test 'equal))
|
||||
(env-names
|
||||
(cl-loop for env in envs
|
||||
for env-name = (if (eq base-env env-name) "base"
|
||||
(file-name-nondirectory env))
|
||||
do (if (gethash env-name dupe-name-map)
|
||||
(puthash env-name 'dupe dupe-name-map)
|
||||
(puthash env-name t dupe-name-map))
|
||||
collect env-name)))
|
||||
(cl-loop for env in envs
|
||||
for env-name in env-names
|
||||
for name = (if (eq (gethash env-name dupe-name-map) 'dupe)
|
||||
env env-name)
|
||||
collect (cons name env))))
|
||||
|
||||
(defun micromamba--parse-script-buffer ()
|
||||
"Parse bash script buffer generated by micromamba.
|
||||
|
||||
E.g. micromamba shell -s bash activate <prefix>.
|
||||
|
||||
Returns an alist with the following keys:
|
||||
- path
|
||||
- vars-unset
|
||||
- vars-export
|
||||
- scripts."
|
||||
(let (path vars-unset vars-export scripts)
|
||||
(while (not (eobp))
|
||||
(cond
|
||||
((looking-at (rx bol "export PATH='"))
|
||||
(setq path
|
||||
(split-string (buffer-substring-no-properties
|
||||
(+ 13 (point)) (1- (point-at-eol)))
|
||||
":")))
|
||||
((looking-at (rx bol "unset"))
|
||||
(push
|
||||
(buffer-substring-no-properties (+ 6 (point)) (point-at-eol))
|
||||
vars-unset) )
|
||||
((looking-at (rx bol "export"))
|
||||
(save-excursion
|
||||
(let ((var-point (+ 7 (point))))
|
||||
(re-search-forward (rx "="))
|
||||
(let ((var-name (buffer-substring-no-properties var-point (1- (point))))
|
||||
(var-contents (buffer-substring-no-properties
|
||||
(point) (point-at-eol))))
|
||||
(when (string-match-p (rx bos "'" (* nonl) "'" eos) var-contents)
|
||||
(setq var-contents
|
||||
(substring var-contents 1 (1- (length var-contents)))))
|
||||
(push (cons var-name var-contents) vars-export)))))
|
||||
((looking-at (rx bol ". \""))
|
||||
(push (buffer-substring-no-properties (+ 4 (point))
|
||||
(1- (point-at-eol)))
|
||||
scripts)))
|
||||
(forward-line))
|
||||
`((path . ,path)
|
||||
(vars-unset . ,vars-unset)
|
||||
(vars-export . ,vars-export)
|
||||
(scripts . ,scripts))))
|
||||
|
||||
(defun micromamba--get-activation-parameters (prefix)
|
||||
"Get activation parameters for the environment PREFIX.
|
||||
|
||||
The parameters value is an alist as defined by
|
||||
`micromamba--parse-script-buffer'."
|
||||
(with-temp-buffer
|
||||
(call-process micromamba-executable nil t nil
|
||||
"shell" "-s" "bash" "activate" prefix)
|
||||
(goto-char (point-min))
|
||||
(micromamba--parse-script-buffer)))
|
||||
|
||||
(defun micromamba--get-deactivation-parameters ()
|
||||
"Get deactivation parameters for the current evironment.
|
||||
|
||||
The parameters value is an alist as defined by
|
||||
`micromamba--parse-script-buffer'."
|
||||
(with-temp-buffer
|
||||
(call-process micromamba-executable nil t nil
|
||||
"shell" "-s" "bash" "deactivate")
|
||||
(goto-char (point-min))
|
||||
(micromamba--parse-script-buffer)))
|
||||
|
||||
(defun micromamba--apply-env (parameters)
|
||||
"Apply PARAMETERS to the current environment.
|
||||
|
||||
The parameters value is an alist as defined by
|
||||
`micromamba--parse-script-buffer'."
|
||||
(setq exec-path (alist-get 'path parameters))
|
||||
(setenv "PATH" (string-join (alist-get 'path parameters) ":"))
|
||||
(dolist (var-name (alist-get 'vars-unset parameters))
|
||||
(setenv var-name nil))
|
||||
(dolist (var (alist-get 'vars-export parameters))
|
||||
(setenv (car var) (cdr var)))
|
||||
(setq eshell-path-env (getenv "PATH")))
|
||||
|
||||
;;;###autoload
|
||||
(defun micromamba-activate (prefix)
|
||||
"Switch to environment with PREFIX (path). Prompt if called interactively."
|
||||
(interactive
|
||||
(list (let ((envs (micromamba-envs)))
|
||||
(alist-get
|
||||
(completing-read "Choose a micromamba environment: " envs
|
||||
nil t)
|
||||
envs nil nil #'equal))))
|
||||
(micromamba-deactivate)
|
||||
(setq micromamba-env-current-prefix prefix)
|
||||
(run-hooks 'micromamba-preactivate-hook)
|
||||
;; conda.el was doing that, so why not?
|
||||
(pythonic-activate prefix)
|
||||
(setq python-shell-virtualenv-root prefix)
|
||||
(micromamba--apply-env
|
||||
(micromamba--get-activation-parameters prefix))
|
||||
(run-hooks 'micromamba-postactivate-hook))
|
||||
|
||||
;;;###autoload
|
||||
(defun micromamba-deactivate ()
|
||||
"Deactivate the current environment."
|
||||
(interactive)
|
||||
(when (bound-and-true-p micromamba-env-current-prefix)
|
||||
(run-hooks 'micromamba-predeactivate-hook)
|
||||
(setq python-shell-virtualenv-root nil)
|
||||
(micromamba--apply-env
|
||||
(micromamba--get-deactivation-parameters))
|
||||
(setq micromamba-env-current-prefix nil)
|
||||
(run-hooks 'micromamba-postdeactivate-hook)))
|
||||
|
||||
;;; micromamba.el ends here
|
||||
Loading…
Add table
Reference in a new issue