diff --git a/README.md b/README.md index 8c791f2..9f57927 100644 --- a/README.md +++ b/README.md @@ -180,11 +180,23 @@ Strongly recommend to use ;; The interval of checking github. (setq doom-modeline-github-interval (* 30 60)) -;; Whether display environment version or not. +;; Whether display environment version or not (setq doom-modeline-env-version t) +;; Or for individual languages +(setq doom-modeline-env-enable-python t) +(setq doom-modeline-env-enable-ruby t) +(setq doom-modeline-env-enable-perl t) +(setq doom-modeline-env-enable-go t) +(setq doom-modeline-env-enable-elixir t) +(setq doom-modeline-env-enable-rust t) -;; What executable of Python will be used (if nil nothing will be showed). -(setq doom-modeline-python-executable "python") +;; Change the executables to use for the language version string +(setq doom-modeline-env-python-executable "python") +(setq doom-modeline-env-ruby-executable "ruby") +(setq doom-modeline-env-perl-executable "perl") +(setq doom-modeline-env-go-executable "go") +(setq doom-modeline-env-elixir-executable "iex") +(setq doom-modeline-env-rust-executable "rustc") ;; Whether display mu4e notifications or not. Requires `mu4e-alert' package. (setq doom-modeline-mu4e t) diff --git a/doom-modeline-core.el b/doom-modeline-core.el index 7d1c2da..4e8f1f3 100644 --- a/doom-modeline-core.el +++ b/doom-modeline-core.el @@ -123,9 +123,6 @@ The icons may not be showed correctly in terminal and on Windows.") "Whether display environment version or not.") (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 "Whether display mu4e notifications or not. Requires `mu4e-alert' package.") diff --git a/doom-modeline-env.el b/doom-modeline-env.el index 468998e..ca9a879 100644 --- a/doom-modeline-env.el +++ b/doom-modeline-env.el @@ -44,19 +44,33 @@ Example: '(\"--version\") ") "A function that returns version number from a programs --version (or similar) command. 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 () "Update environment info on mode-line." (when (and doom-modeline-env-version doom-modeline-env--command - (executable-find doom-modeline-env--command) doom-modeline-env--command-args doom-modeline-env--parser) - (let ((default-directory (doom-modeline-project-root))) - (doom-modeline-env--get doom-modeline-env--command - doom-modeline-env--command-args - (lambda (prog-version) - (setq doom-modeline-env--version - (funcall doom-modeline-env--parser prog-version))))))) + (let ((default-directory (doom-modeline-project-root)) + (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 + (lambda (prog-version) + (with-current-buffer buffer + (setq doom-modeline-env--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) (with-no-warnings @@ -89,55 +103,63 @@ Example: (ignore-errors (funcall parser line)))))) -;; -;; Parser -;; +(cl-defmacro doom-modeline-def-env (name &key hooks command parser) + "Defines a handler for updating & displaying a version string for a language. -(defun doom-modeline-env--ruby (line) - "Parse Ruby version from LINE." - (car (split-string - (cadr - (split-string line)) - "p"))) - -(defun doom-modeline-env--elixir (line) - "Parse Elixir version from LINE." - (cadr - (split-string line))) - -(defun doom-modeline-env--rustc (line) - "Parse Rust version from LINE." - (car - (split-string - (cadr - (split-string line)) - "-"))) - -(defun doom-modeline-env--go (line) - "Parse Go version from LINE." - (cadr - (split-string - (cadr - (cdr - (split-string - line))) - "go"))) - -(defun doom-modeline-env--perl (line) - "Parse Perl version from LINE." - (cadr - (split-string - (car - (split-string - (cadr - (split-string line "(")) - ")")) - "v"))) - -(defun doom-modeline-env--python (line) - "Parse Python version from LINE." - (cadr - (split-string line))) +NAME is an unquoted symbol representing the handler's unique ID. +HOOKS is a list of hook symbols where this handler should be triggered. +COMMAND should be a function that returns a shell command and its arguments (as + a list). It is run on HOOKS. It takes no arguments. +PARSER should be a function for parsing COMMAND's output line-by-line, to + extract the version string." + (declare (indent defun)) + (unless (and hooks command parser) + (error "'%s' env is missing either :hooks, :command or :parser" name)) + (let ((parse-fn (intern (format "doom-modeline-env--%s-parse" name))) + (action-fn (intern (format "doom-modeline-env--%s-args" name))) + (setup-fn (intern (format "doom-modeline-env-setup-%s" name))) + (update-fn (intern (format "doom-modeline-env-update-%s" name))) + (enable-var (intern (format "doom-modeline-env-enable-%s" name))) + (command-var (intern (format "doom-modeline-env-%s-command" name))) + (parser-var (intern (format "doom-modeline-env-%s-parser-fn" name))) + (exe-var (intern (format "doom-modeline-env-%s-executable" name)))) + (macroexp-progn + `((defvar ,enable-var t + (format "Whether to display the version string for %s buffers." ',name)) + (defvar ,command-var ',action-fn + (concat "A function that returns the shell command and arguments (as a list) to\n" + "produce a version string.")) + (defvar ,parser-var ',parse-fn + (format "The function for parsing each line of `%s's output." ',command-var)) + (defvar ,exe-var nil + (format (concat "What executable to use for the version indicator in %s buffers.\n\n" + "If nil, the default binary for this language is used.") + ',name)) + (defalias ',parse-fn ,parser + (format "The line parser for %s buffers.\n\nUsed by `%s'." + ',name ',update-fn)) + (defalias ',action-fn ,command + (format "The command resolver for %s buffers.\n\nUsed by `%s'." + ',name ',update-fn)) + (defalias ',setup-fn + (lambda () + (if enable-local-variables + (add-hook 'hack-local-variables-hook #',update-fn nil t) + (,update-fn))) + (format "Prepares the modeline to later display the %s version string." + ',name)) + (defalias ',update-fn + (lambda () + (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)) + (let ((hooks ',(eval hooks))) + (dolist (hook (if (listp hooks) hooks (list hooks))) + (add-hook hook #',setup-fn))))))) ;; @@ -145,43 +167,74 @@ Example: ;; Versions, support Python, Ruby, Perl and Golang, etc. ;; -(add-hook 'python-mode-hook - (lambda () - (cond ((and (fboundp 'pipenv-project-p) (pipenv-project-p) (executable-find "pipenv")) - (setq doom-modeline-env--parser 'doom-modeline-env--python) - (setq doom-modeline-env--command "pipenv") - (setq doom-modeline-env--command-args '("run" "python" "--version"))) - ((and doom-modeline-python-executable - (executable-find doom-modeline-python-executable)) - (setq doom-modeline-env--parser 'doom-modeline-env--python) - (setq doom-modeline-env--command doom-modeline-python-executable) - (setq doom-modeline-env--command-args '("--version")))))) -(add-hook 'ruby-mode-hook - (lambda () - (setq doom-modeline-env--command "ruby") - (setq doom-modeline-env--command-args '("--version")) - (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))) +;;;###autoload (autoload 'doom-modeline-env-setup-python "doom-modeline-env") +(doom-modeline-def-env python + :hooks 'python-mode-hook + :command (lambda () (cond ((and (fboundp 'pipenv-project-p) + (pipenv-project-p)) + (list "pipenv" "run" + (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")) + ((list (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")))) + :parser (lambda (line) (cadr (split-string line)))) -(add-hook 'elixir-mode-hook - (lambda () - (setq doom-modeline-env--command "iex") - (setq doom-modeline-env--command-args '("--version")) - (setq doom-modeline-env--parser 'doom-modeline-env--elixir))) -(add-hook 'rust-mode-hook - (lambda () - (setq doom-modeline-env--command "rustc") - (setq doom-modeline-env--command-args '("--version")) - (setq doom-modeline-env--parser 'doom-modeline-env--rustc))) +;;;###autoload (autoload 'doom-modeline-env-setup-ruby "doom-modeline-env") +(doom-modeline-def-env ruby + :hooks '(ruby-mode-hook enh-ruby-mode-hook) + :command (lambda () (list (or doom-modeline-env-ruby-executable "ruby") "--version")) + :parser (lambda (line) + (car (split-string + (cadr + (split-string line)) + "p")))) + +;;;###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 (line) (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) diff --git a/test/doom-modeline-env-test.el b/test/doom-modeline-env-test.el index a52d47f..31e5252 100644 --- a/test/doom-modeline-env-test.el +++ b/test/doom-modeline-env-test.el @@ -32,27 +32,27 @@ (ert-deftest doom-modeline-env--ruby/parse-ruby-version-string () (should - (string= (doom-modeline-env--ruby "ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]") + (string= (doom-modeline-env--ruby-parse "ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]") "2.3.3"))) (ert-deftest doom-modeline-env--elixir/parse-elixr-version-string () (should - (string= (doom-modeline-env--elixir "IEx 1.7.4 (compiled with Erlang/OTP 21)") + (string= (doom-modeline-env--elixir-parse "IEx 1.7.4 (compiled with Erlang/OTP 21)") "1.7.4"))) (ert-deftest doom-modeline-env--rustc/parse-rustc-version-string () (should - (string= (doom-modeline-env--rustc "rustc 1.32.0-nightly (14997d56a 2018-12-05)") + (string= (doom-modeline-env--rust-parse "rustc 1.32.0-nightly (14997d56a 2018-12-05)") "1.32.0"))) (ert-deftest doom-modeline-env--go/parse-go-version-string () (should - (string= (doom-modeline-env--go "go version go1.11.4 darwin/amd64") + (string= (doom-modeline-env--go-parse "go version go1.11.4 darwin/amd64") "1.11.4"))) (ert-deftest doom-modeline-env--perl/parse-perl-version-string () (should - (string= (doom-modeline-env--perl + (string= (doom-modeline-env--perl-parse "This is perl 5, version 18, subversion 2 (v5.18.2) built for darwin-thread-multi-2level (with 2 registered patches, see perl -V for more detail) @@ -68,7 +68,7 @@ Internet, point your browser at http://www.perl.org/, the Perl Home Page.") (ert-deftest doom-modeline-env--python/parse-python-version-string () (should - (string= (doom-modeline-env--python "Python 2.7.15") + (string= (doom-modeline-env--python-parse "Python 2.7.15") "2.7.15"))) ;;; doom-modeline-env-test.el ends here