Rewrite env system

+ Initializes the modeline segment on hack-local-variables-hook, which
  is triggered as late as possible in the major mode activation process,
  when file/dir-local variables have been processed. This allows users
  to exploit file/dir-local variables to modify the behavior of this
  mode-line segment.
+ Add doom-modeline-{before,after}-update-env-hook hooks. Useful for
  injecting environment detection for things like conda and virtualenv.
+ Add customizable executable variables for each language. e.g.
  doom-modeline-env-python-executable
+ Simplify language env definition into a macro.
+ Replaces the version string with "..." while we wait for a new one.
+ Add support for enh-ruby-mode.
This commit is contained in:
Henrik Lissner 2019-03-06 20:46:02 -05:00
parent 80bc70fa82
commit a73cc3d112
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
2 changed files with 143 additions and 94 deletions

View file

@ -123,9 +123,6 @@ The icons may not be showed correctly in terminal and on Windows.")
"Whether display environment version or not.") "Whether display environment version or not.")
(define-obsolete-variable-alias 'doom-modeline-version 'doom-modeline-env-version "1.7.4") (define-obsolete-variable-alias 'doom-modeline-version 'doom-modeline-env-version "1.7.4")
(defvar doom-modeline-python-executable "python"
"What executable of Python will be used (if nil nothing will be showed).")
(defvar doom-modeline-mu4e t (defvar doom-modeline-mu4e t
"Whether display mu4e notifications or not. Requires `mu4e-alert' package.") "Whether display mu4e notifications or not. Requires `mu4e-alert' package.")

View file

@ -44,19 +44,33 @@ Example: '(\"--version\") ")
"A function that returns version number from a programs --version (or similar) command. "A function that returns version number from a programs --version (or similar) command.
Example: 'doom-modeline-env--ruby") Example: 'doom-modeline-env--ruby")
(defvar doom-modeline-load-string "..."
"What to dispaly as the version while a new one is being loaded.")
(defvar doom-modeline-after-update-env-hook nil
"Hooks that run after the modeline version string is updated.")
(defvar doom-modeline-before-update-env-hook nil
"Hooks that run before the modeline version string is updated.")
(defun doom-modeline-update-env () (defun doom-modeline-update-env ()
"Update environment info on mode-line." "Update environment info on mode-line."
(when (and doom-modeline-env-version (when (and doom-modeline-env-version
doom-modeline-env--command doom-modeline-env--command
(executable-find doom-modeline-env--command)
doom-modeline-env--command-args doom-modeline-env--command-args
doom-modeline-env--parser) doom-modeline-env--parser)
(let ((default-directory (doom-modeline-project-root))) (let ((default-directory (doom-modeline-project-root))
(doom-modeline-env--get doom-modeline-env--command (buffer (current-buffer)))
(run-hooks 'doom-modeline-before-update-env-hook)
(setq doom-modeline-env--version doom-modeline-load-string)
(doom-modeline-env--get
doom-modeline-env--command
doom-modeline-env--command-args doom-modeline-env--command-args
(lambda (prog-version) (lambda (prog-version)
(with-current-buffer buffer
(setq doom-modeline-env--version (setq doom-modeline-env--version
(funcall doom-modeline-env--parser prog-version))))))) (funcall doom-modeline-env--parser prog-version))
(run-hooks 'doom-modeline-after-update-env-hook)))))))
(add-hook 'find-file-hook #'doom-modeline-update-env) (add-hook 'find-file-hook #'doom-modeline-update-env)
(with-no-warnings (with-no-warnings
@ -89,55 +103,62 @@ Example:
(ignore-errors (ignore-errors
(funcall parser line)))))) (funcall parser line))))))
;; (cl-defmacro doom-modeline-def-env (name &key hooks command parser)
;; Parser "Defines a handler for updating & displaying a version string for a language.
;;
(defun doom-modeline-env--ruby (line) NAME is an unquoted symbol representing the handler's unique ID.
"Parse Ruby version from LINE." HOOKS is a list of hook symbols where this handler should be triggered.
(car (split-string COMMAND should be a function that returns a shell command and its arguments (as
(cadr a list). It is run on HOOKS. It takes no arguments.
(split-string line)) PARSER should be a function for parsing COMMAND's output line-by-line, to
"p"))) extract the version string."
(declare (indent defun))
(defun doom-modeline-env--elixir (line) (unless (and hooks command parser)
"Parse Elixir version from LINE." (error "'%s' env is missing either :hooks, :command or :parser" name))
(cadr (let ((parse-fn (intern (format "doom-modeline-env--%s-parse" name)))
(split-string line))) (action-fn (intern (format "doom-modeline-env--%s-args" name)))
(setup-fn (intern (format "doom-modeline-env-setup-%s" name)))
(defun doom-modeline-env--rustc (line) (update-fn (intern (format "doom-modeline-env-update-%s" name)))
"Parse Rust version from LINE." (enable-var (intern (format "doom-modeline-env-enable-%s" name)))
(car (command-var (intern (format "doom-modeline-env-%s-command" name)))
(split-string (parser-var (intern (format "doom-modeline-env-%s-parser-fn" name)))
(cadr (exe-var (intern (format "doom-modeline-env-%s-executable" name))))
(split-string line)) (macroexp-progn
"-"))) `((defvar ,enable-var t
(format "Whether to display the version string for %s buffers." ',name))
(defun doom-modeline-env--go (line) (defvar ,command-var ',action-fn
"Parse Go version from LINE." (concat "A function that returns the shell command and arguments (as a list) to\n"
(cadr "produce a version string."))
(split-string (defvar ,parser-var ',parse-fn
(cadr (format "The function for parsing each line of `%s's output." ',command-var))
(cdr (defvar ,exe-var nil
(split-string (format (concat "What executable to use for the version indicator in %s buffers.\n\n"
line))) "If nil, the default binary for this language is used.")
"go"))) ',name))
(defalias ',parse-fn ,parser
(defun doom-modeline-env--perl (line) (format "The line parser for %s buffers.\n\nUsed by `%s'."
"Parse Perl version from LINE." ',name ',update-fn))
(cadr (defalias ',action-fn ,command
(split-string (format "The command resolver for %s buffers.\n\nUsed by `%s'."
(car ',name ',update-fn))
(split-string (defalias ',setup-fn
(cadr (lambda ()
(split-string line "(")) (if enable-local-variables
")")) (add-hook 'hack-local-variables-hook #',update-fn nil t)
"v"))) (,update-fn)))
(format "Prepares the modeline to later display the %s version string."
(defun doom-modeline-env--python (line) ',name))
"Parse Python version from LINE." (defalias ',update-fn
(cadr (lambda ()
(split-string line))) (when ,enable-var
(when-let* ((command (funcall ,command-var)))
(setq doom-modeline-env--command (car command)
doom-modeline-env--command-args (cdr command)
doom-modeline-env--parser ,parser-var)
(doom-modeline-update-env))))
(format "Updates the %s version string in the modeline." ',name))
(dolist (hook ',(doom-enlist (eval hooks)))
(add-hook hook #',setup-fn))))))
;; ;;
@ -145,43 +166,74 @@ Example:
;; Versions, support Python, Ruby, Perl and Golang, etc. ;; Versions, support Python, Ruby, Perl and Golang, etc.
;; ;;
(add-hook 'python-mode-hook ;;;###autoload (autoload 'doom-modeline-env-setup-python "doom-modeline-env")
(lambda () (doom-modeline-def-env python
(cond ((and (fboundp 'pipenv-project-p) (pipenv-project-p) (executable-find "pipenv")) :hooks 'python-mode-hook
(setq doom-modeline-env--parser 'doom-modeline-env--python) :command (lambda () (cond ((and (fboundp 'pipenv-project-p)
(setq doom-modeline-env--command "pipenv") (pipenv-project-p))
(setq doom-modeline-env--command-args '("run" "python" "--version"))) (list "pipenv" "run"
((and doom-modeline-python-executable (or doom-modeline-env-python-executable
(executable-find doom-modeline-python-executable)) python-shell-interpreter
(setq doom-modeline-env--parser 'doom-modeline-env--python) "python")
(setq doom-modeline-env--command doom-modeline-python-executable) "--version"))
(setq doom-modeline-env--command-args '("--version")))))) ((list (or doom-modeline-env-python-executable
(add-hook 'ruby-mode-hook python-shell-interpreter
(lambda () "python")
(setq doom-modeline-env--command "ruby") "--version"))))
(setq doom-modeline-env--command-args '("--version")) :parser (lambda (line) (cadr (split-string line))))
(setq doom-modeline-env--parser 'doom-modeline-env--ruby)))
(add-hook 'perl-mode-hook
(lambda ()
(setq doom-modeline-env--command "perl")
(setq doom-modeline-env--command-args '("--version"))
(setq doom-modeline-env--parser 'doom-modeline-env--perl)))
(add-hook 'go-mode-hook
(lambda ()
(setq doom-modeline-env--command "go")
(setq doom-modeline-env--command-args '("version"))
(setq doom-modeline-env--parser 'doom-modeline-env--go)))
(add-hook 'elixir-mode-hook ;;;###autoload (autoload 'doom-modeline-env-setup-ruby "doom-modeline-env")
(lambda () (doom-modeline-def-env ruby
(setq doom-modeline-env--command "iex") :hooks '(ruby-mode-hook enh-ruby-mode-hook)
(setq doom-modeline-env--command-args '("--version")) :command (lambda () (list (or doom-modeline-env-ruby-executable "ruby") "--version"))
(setq doom-modeline-env--parser 'doom-modeline-env--elixir))) :parser (lambda (line)
(add-hook 'rust-mode-hook (car (split-string
(lambda () (cadr
(setq doom-modeline-env--command "rustc") (split-string line))
(setq doom-modeline-env--command-args '("--version")) "p"))))
(setq doom-modeline-env--parser 'doom-modeline-env--rustc)))
;;;###autoload (autoload 'doom-modeline-env-setup-perl "doom-modeline-env")
(doom-modeline-def-env perl
:hooks 'perl-mode-hook
:command (lambda () (list (or doom-modeline-env-perl-executable "perl") "--version"))
:parser (lambda (line)
(cadr
(split-string
(car
(split-string
(cadr
(split-string line "("))
")"))
"v"))))
;;;###autoload (autoload 'doom-modeline-env-setup-go "doom-modeline-env")
(doom-modeline-def-env go
:hooks 'go-mode-hook
:command (lambda () (list (or doom-modeline-env-go-executable "go") "version"))
:parser (lambda (line)
(cadr
(split-string
(cadr
(cdr
(split-string line)))
"go"))))
;;;###autoload (autoload 'doom-modeline-env-setup-elixir "doom-modeline-env")
(doom-modeline-def-env elixir
:hooks 'elixir-mode-hook
:command (lambda () (list (or doom-modeline-env-elixir-executable "iex") "--version"))
:parser (lambda () (cadr (split-string line))))
;;;###autoload (autoload 'doom-modeline-env-setup-rust "doom-modeline-env")
(doom-modeline-def-env rust
:hooks 'rust-mode-hook
:command (lambda () (list (or doom-modeline-env-rust-executable "rustc") "--version"))
:parser (lambda (line)
(car
(split-string
(cadr
(split-string line))
"-"))))
(provide 'doom-modeline-env) (provide 'doom-modeline-env)