From 3eb87019197025543a39410a9cb1762f916fe2b8 Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Fri, 11 Jan 2019 16:34:47 -0500 Subject: [PATCH] Change to using start-process to capture command version information --- doom-modeline.el | 75 +++++++++++++++------------- doom-version-parser.el | 86 ++++++++++++++++++++++++++++++++ test/doom-version-parser-test.el | 71 ++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 36 deletions(-) create mode 100644 doom-version-parser.el create mode 100644 test/doom-version-parser-test.el diff --git a/doom-modeline.el b/doom-modeline.el index 73d0093..9a650d6 100644 --- a/doom-modeline.el +++ b/doom-modeline.el @@ -76,6 +76,7 @@ (require 'eldoc-eval) (require 'shrink-path) (require 'subr-x) +(require 'doom-version-parser) (when (>= emacs-major-version 26) (require 'project)) @@ -538,7 +539,10 @@ If DEFAULT is non-nil, set the default mode-line for all buffers." ;; Show version string for multi-version managers like rvm, rbenv, pyenv, etc. (defvar-local doom-modeline-env-version nil) -(defvar-local doom-modeline-env-command nil) + +(defvar-local doom-modeline-env-command nil "A program that we're looking to extract version information from. Ex: \"ruby\"") +(defvar-local doom-modeline-env-command-args nil "A list of arguments to pass to `doom-modeline-env-command` to extract the version from. Ex: '(\"--version\") ") +(defvar-local doom-modeline-env-parser nil "A function that returns version number from a programs --version (or similar) command. Ex: 'doom-version-parser--ruby") (add-hook 'find-file-hook #'doom-modeline-update-env) (with-no-warnings (if (boundp 'after-focus-change-function) @@ -546,13 +550,16 @@ If DEFAULT is non-nil, set the default mode-line for all buffers." (add-hook 'focus-in-hook #'doom-modeline-update-env))) (defun doom-modeline-update-env () "Update environment info on mode-line." - (when (and doom-modeline-version doom-modeline-env-command) - (let ((default-directory (doom-modeline-project-root)) - (s (shell-command-to-string doom-modeline-env-command))) - (setq doom-modeline-env-version (if (string-match "[ \t\n\r]+\\'" s) - (replace-match "" t t s) - s))))) - + (when (and doom-modeline-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-version-parser--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))))))) ;; ;; Modeline helpers @@ -2039,45 +2046,41 @@ mouse-1: Toggle Debug on Quit" ;; 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") - (executable-find "cut") (executable-find "sed") (executable-find "xargs")) - (setq doom-modeline-env-command - "pipenv run python --version 2>&1 | cut -d' ' -f2 | sed -n '1p' | xargs echo 'Pipenv'")) + (cond ((and (fboundp 'pipenv-project-p) (pipenv-project-p) (executable-find "pipenv")) + (setq doom-modeline-env-parser 'doom-version-parser--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) - (executable-find "cut") (executable-find "sed")) - (setq doom-modeline-env-command - (concat doom-modeline-python-executable " --version 2>&1 | cut -d' ' -f2 | sed -n '1p'")))))) + (executable-find doom-modeline-python-executable)) + (setq doom-modeline-env-parser 'doom-version-parser--python) + (setq doom-modeline-env-command doom-modeline-python-executable) + (setq doom-modeline-env-command-args '("--version")))))) (add-hook 'ruby-mode-hook (lambda () - (when (and (executable-find "ruby") - (executable-find "cut") (executable-find "sed")) - (setq doom-modeline-env-command - "ruby --version 2>&1 | cut -d' ' -f2 | sed -n '1p'")))) + (setq doom-modeline-env-command "ruby") + (setq doom-modeline-env-command-args '("--version")) + (setq doom-modeline-env-parser 'doom-version-parser--ruby))) (add-hook 'perl-mode-hook (lambda () - (when (and (executable-find "perl") (executable-find "cut") - (executable-find "tr") (executable-find "sed")) - (setq doom-modeline-env-command - "perl --version 2>&1 | cut -d'(' -f2 | cut -d')' -f1 | tr -d 'v' | sed -n '2p'")))) + (setq doom-modeline-env-command "perl") + (setq doom-modeline-env-command-args '("--version")) + (setq doom-modeline-env-parser 'doom-version-parser--perl))) (add-hook 'go-mode-hook (lambda () - (when (and (executable-find "go") (executable-find "cut") - (executable-find "tr") (executable-find "sed")) - (setq doom-modeline-env-command - "go version 2>&1 | cut -d' ' -f3 | tr -d 'go' | sed -n '1p'")))) + (setq doom-modeline-env-command "go") + (setq doom-modeline-env-command-args '("version")) + (setq doom-modeline-env-parser 'doom-version-parser--go))) + (add-hook 'elixir-mode-hook (lambda () - (when (and (executable-find "iex") - (executable-find "cut") (executable-find "sed")) - (setq doom-modeline-env-command - "iex --version 2>&1 | cut -d' ' -f2 | sed -n '1p'")))) + (setq doom-modeline-env-command "iex") + (setq doom-modeline-env-command-args '("--version")) + (setq doom-modeline-env-parser 'doom-version-parser--elixir))) (add-hook 'rust-mode-hook (lambda () - (when (and (executable-find "rustc") - (executable-find "cut") (executable-find "sed")) - (setq doom-modeline-env-command - "rustc --version 2>&1 | cut -d' ' -f2 | sed -n '1p'")))) + (setq doom-modeline-env-command "rustc") + (setq doom-modeline-env-command-args '("--version")) + (setq doom-modeline-env-parser 'doom-version-parser--rustc))) ;; Ensure modeline is inactive when Emacs is unfocused (and active otherwise) diff --git a/doom-version-parser.el b/doom-version-parser.el new file mode 100644 index 0000000..219fdbb --- /dev/null +++ b/doom-version-parser.el @@ -0,0 +1,86 @@ +;;; doom-version-parser.el --- A version parser for doom-modeline -*- lexical-binding: t -*- + +;; Copyright (C) 2019 Justin Barclay + +;; Version: 1.4.5 +;; +;; 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 2, 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; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; + +(require 'subr-x) + +(defun doom-version-parser--ruby (line) + (car (split-string + (cadr + (split-string line)) + "p"))) + +(defun doom-version-parser--elixir (line) + (cadr + (split-string line))) + +(defun doom-version-parser--rustc (line) + (car + (split-string + (cadr + (split-string line)) + "-"))) + +(defun doom-version-parser--go (line) + (cadr + (split-string + (cadr + (cdr + (split-string + line))) + "go"))) + +(defun doom-version-parser--perl (line) + (cadr + (split-string + (car + (split-string + (cadr + (split-string line "(")) + ")")) + "v"))) + +(defun doom-version-parser--python (line) + (cadr + (split-string line))) + +(defun doom-version-parser--get (prog args callback) + "Starts a sub process using prog and applies the args to the sub process. + Once it recieves information from STDOUT, it closes off the subprocess and + passes on the information into the callback. + Ex: (doom-version-parser--get \"ruby\" '(\"version\") (lambda (line) (message (doom-modeline-parser--ruby)))" + (let ((proc (apply 'start-process + (append ;; Flaten process-args into a single list so we can handle variadic length args + (list "doom-modeline-prog" "doom-modeline-prog" prog) + args))) + (parser callback)) + (set-process-filter proc (lambda (proc1 line) + (defvar old-buffer-query-functions kill-buffer-query-functions) ;; Store old query function + (setq kill-buffer-query-functions nil) ;; No need to query user when we kill this buffer and process + (kill-process proc1) ;; Clean up after ourselves + (kill-buffer "doom-modeline-prog") + (setq kill-buffer-query-functions old-buffer-query-functions) ;; let's restore everthing + (funcall parser line))) + nil)) + +(provide 'doom-version-parser) + +;;; doom-version-parser.el ends here diff --git a/test/doom-version-parser-test.el b/test/doom-version-parser-test.el new file mode 100644 index 0000000..8f49c58 --- /dev/null +++ b/test/doom-version-parser-test.el @@ -0,0 +1,71 @@ +;;; doom-version-parser-test.el --- Unit tests for doom-version-parser -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Justin Barclay + +;; 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 2, 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; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; + +;;; Commentary: +;; +;; Unit tests for doom-version-parser +;; + +;;; Code: +(ert-deftest doom-version-parser--ruby/parse-ruby-version-string () + (should + (string= (doom-version-parser--ruby "ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]") + "2.3.3"))) + +(ert-deftest doom-version-parser--elixir/parse-elixr-version-string () + (should + (string= (doom-version-parser--elixir "IEx 1.7.4 (compiled with Erlang/OTP 21)") + "1.7.4"))) + +(ert-deftest doom-version-parser--rustc/parse-rustc-version-string () + (should + (string= (doom-version-parser--rustc "rustc 1.32.0-nightly (14997d56a 2018-12-05)") + "1.32.0"))) + +(ert-deftest doom-version-parser--go/parse-go-version-string () + (should + (string= (doom-version-parser--go "go version go1.11.4 darwin/amd64") + "1.11.4"))) + +(ert-deftest doom-version-parser--perl/parse-perl-version-string () + (should + (string= (doom-version-parser--perl + "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) + +Copyright 1987-2013, Larry Wall + +Perl may be copied only under the terms of either the Artistic License or the +GNU General Public License, which may be found in the Perl 5 source kit. + +Complete documentation for Perl, including FAQ lists, should be found on +this system using \"man perl\" or \"perldoc perl\". If you have access to the +Internet, point your browser at http://www.perl.org/, the Perl Home Page.") + "5.18.2"))) + +(ert-deftest doom-version-parser--python/parse-python-version-string () + (should + (string= (doom-version-parser--python "Python 2.7.15") + "2.7.15"))) + +;;; doom-version-parser-test.el ends here