From 5c3892b1a612e90841aaa79798e3252ac23e4772 Mon Sep 17 00:00:00 2001 From: Ade Attwood Date: Sat, 19 Feb 2022 20:19:43 +0000 Subject: [PATCH] feat(emacs): add custom projectile project type Add a new project type for Practically Makefile projects that are using conventional tools. This implements a few features all based around PHP and JavaScript projects. The most notable features are: - Compilation error detection for Jest JS testing framework - Compilation error detection for Psalm PHP static analyser - Alternate file support for Codeception "Cest" files - JS test commands supporting "Jest" - PHP test commands supporting "Codeception", "PHP Unit" and "Simple PHP Unit" - Full project test support detecting the file type and the test command to run --- site-modules/core/files/emacs/init.el | 6 +- .../core/files/emacs/src/projectile.el | 98 +++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/site-modules/core/files/emacs/init.el b/site-modules/core/files/emacs/init.el index 55ccd5b..b691d46 100644 --- a/site-modules/core/files/emacs/init.el +++ b/site-modules/core/files/emacs/init.el @@ -33,7 +33,6 @@ (load-file (expand-file-name "src/file-operations.el" user-emacs-directory)) (load-file (expand-file-name "src/evil.el" user-emacs-directory)) (load-file (expand-file-name "src/ivy.el" user-emacs-directory)) -(load-file (expand-file-name "src/projectile.el" user-emacs-directory)) (load-file (expand-file-name "src/treemacs.el" user-emacs-directory)) (load-file (expand-file-name "src/term.el" user-emacs-directory)) (load-file (expand-file-name "src/language-tool.el" user-emacs-directory)) @@ -62,6 +61,10 @@ (load-file (expand-file-name "src/lang/shell.el" user-emacs-directory)) (load-file (expand-file-name "src/lang/c.el" user-emacs-directory)) +;; Load the projectile module last so we can override compilation errors regexp +;; without other modules affecting it after +(load-file (expand-file-name "src/projectile.el" user-emacs-directory)) + (use-package general :config (general-create-definer efs/leader-keys @@ -74,6 +77,7 @@ "/" '(counsel-projectile-ag :which-key "Search Project") "TAB" '(evil-switch-to-windows-last-buffer :which-key "Last Buffer") "SPC" '(counsel-M-x :which-key "M-x") + "a" '(projectile-toggle-between-implementation-and-test :which-key "Toggle test and implementation") ";" '(evil-commentary-line :which-key "Comment") ;; Docker "d" '(:ignore t :which-key "Docker") diff --git a/site-modules/core/files/emacs/src/projectile.el b/site-modules/core/files/emacs/src/projectile.el index 0a1f57c..f855e36 100644 --- a/site-modules/core/files/emacs/src/projectile.el +++ b/site-modules/core/files/emacs/src/projectile.el @@ -7,6 +7,7 @@ ;; https://www.practically.io/copyright/ (use-package projectile + :quelpa t :diminish projectile-mode :config (projectile-mode) :custom ((projectile-completion-system 'ivy)) @@ -19,4 +20,101 @@ (setq projectile-switch-project-action #'projectile-dired)) (use-package counsel-projectile + :quelpa t :config (counsel-projectile-mode)) + +(defun projectile--get-php-test-command () + "Get the correct test command for the PHP project. +This will find the test configuration file and work out the correct command to +run from the configuration file" + (cond + ((file-exists-p (concat (projectile-project-root) "vendor/bin/codecept")) "vendor/bin/codecept run --no-ansi") + ((file-exists-p (concat (projectile-project-root) "vendor/bin/simple-phpunit")) "vendor/bin/simple-phpunit --colors=never") + ((file-exists-p (concat (projectile-project-root) "vendor/bin/phpunit")) "vendor/bin/phpunit"))) + +(defun projectile--get-php-test-file-command (file) + "Get the correct command for testing a PHP FILE. +For more details on getting the test command see +`projectile--get-php-test-command`" + (cond + ((file-exists-p (concat (projectile-project-root) "vendor/bin/codecept")) (format "vendor/bin/codecept run --no-ansi %s" file)) + ((file-exists-p (concat (projectile-project-root) "vendor/bin/simple-phpunit")) (format "vendor/bin/simple-phpunit --colors=never %s" file)) + ((file-exists-p (concat (projectile-project-root) "vendor/bin/phpunit")) (format "vendor/bin/phpunit %s" file)))) + +(defun projectile-test-php () + "Test the PHP project." + (interactive) + (let ((default-directory (projectile-project-root))) + (compile (projectile--get-php-test-command)))) + +(defun projectile-test-php-file () + "Test the current file with the PHP command. +If you are in a test file then the 'alternate' file will be run with the test +function for your project" + (interactive) + (let ((default-directory (projectile-project-root))) + (compile (projectile--get-php-test-file-command (projectile-find-matching-test (buffer-file-name)))))) + +(defun projectile--get-js-test-command () + "Test the project with JS command. +The correct test command will be found baised on what configuration you have in +your project" + (cond + ((file-exists-p (concat (projectile-project-root) "jest.config.js")) "jest --no-colors"))) + +(defun projectile--get-js-test-file-command (file) + "Test a FILE with the JS command." + (cond + ((file-exists-p (concat (projectile-project-root) "jest.config.js")) (format "jest --no-colors %s" file)))) + +(defun projectile-test-js () + "Test the current project with JS." + (interactive) + (let ((default-directory (projectile-project-root))) + (compile (projectile--get-js-test-command)))) + +(defun projectile-test-js-file () + "Test the current file with the JS command. +If you are not on a test file then the 'alternate' file will be tested" + (interactive) + (let ((default-directory (projectile-project-root))) + (compile (projectile--get-js-test-file-command (projectile-find-matching-test (buffer-file-name)))))) + +(defun projectile-test-file () + "Test the current file with the project test command. +The command will be found based on the current file extension and the +configuration in the project" + (interactive) + (let ((file-extention (file-name-extension (buffer-file-name)))) + (cond ((string= file-extention "js") (projectile-test-js-file)) + ((string= file-extention "jsx") (projectile-test-js-file)) + ((string= file-extention "tsx") (projectile-test-js-file)) + ((string= file-extention "ts") (projectile-test-js-file)) + ((string= file-extention "php") (projectile-test-php-file))))) + +(setq practically-make/related-files + (list + (projectile-related-files-fn-test-with-suffix "js" ".test") + (projectile-related-files-fn-test-with-suffix "jsx" ".test") + (projectile-related-files-fn-test-with-suffix "ts" ".test") + (projectile-related-files-fn-test-with-suffix "tsx" ".test") + (projectile-related-files-fn-test-with-prefix "php" "Test") + (projectile-related-files-fn-test-with-suffix "php" "Test") + (projectile-related-files-fn-test-with-suffix "php" "Cest"))) + +(projectile-register-project-type 'practically-make '("Makefile" ".ctrc.yml") + :project-file "Makefile" + :configure "make init" + :install "make install" + :test "make test" + :related-files-fn practically-make/related-files) + +;; Add jest errors to the +(add-to-list 'compilation-error-regexp-alist 'jest-erorrs) +(add-to-list 'compilation-error-regexp-alist-alist + '(jest-erorrs "^[ ]*at .* (\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\))" 1 2)) + +;; Add psalm errors so the compilation can pick them up +(add-to-list 'compilation-error-regexp-alist 'psalm-erorrs) +(add-to-list 'compilation-error-regexp-alist-alist + '(psalm-erorrs "^ERROR: .* - \\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)" 1 2))