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
This commit is contained in:
Ade Attwood 2022-02-19 20:19:43 +00:00
parent fc58b21d01
commit 5c3892b1a6
2 changed files with 103 additions and 1 deletions

View file

@ -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")

View file

@ -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))