Skip to content

Commit 95b74fb

Browse files
committed
Handle output of Swift Testing
#191
1 parent 2c0b2b7 commit 95b74fb

File tree

2 files changed

+138
-1
lines changed

2 files changed

+138
-1
lines changed

swift-mode-repl.el

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
(require 'seq)
3636
(require 'subr-x)
3737
(require 'wid-edit)
38+
(require 'compile)
3839

3940
;;;###autoload
4041
(defgroup swift-mode:repl nil
@@ -104,6 +105,19 @@ The string is split by spaces, then unquoted."
104105
:type 'string
105106
:safe #'stringp)
106107

108+
(defcustom swift-mode:swift-testing-command-regexp "\\<swift test\\>"
109+
"Regexp to of command line of Swift Testing.
110+
111+
When the command of `compile' matches this regexp, its
112+
`compilation-error-regexp-alist' is overridden."
113+
:type 'string
114+
:safe #'stringp)
115+
116+
(defcustom swift-mode:resolve-swift-test-file-function
117+
#'swift-mode:resolve-swift-test-file
118+
"Function to resolve Swift Testing files."
119+
:type 'function)
120+
107121
(defvar swift-mode:repl-buffer nil
108122
"Stores the name of the current swift REPL buffer, or nil.")
109123

@@ -959,6 +973,127 @@ the value of `swift-mode:ios-project-scheme' is used."
959973
codesigning-folder-path
960974
product-bundle-identifier))))
961975

976+
(defvar swift-mode:compilation-swift-files nil
977+
"Hash table from Swift filenames in the project to its absolute path.")
978+
979+
(defun swift-mode:setup-swift-testing-buffer ()
980+
"Prepare *compilation* buffer for Swift Testing.
981+
982+
Initialize a hash table from names of swift files to its absolute path.
983+
984+
Adds `ansi-color-compilation-filter' to `compilation-filter-hook'.
985+
986+
Overrides `compilation-error-regexp-alist'."
987+
(setq-local swift-mode:compilation-swift-files nil)
988+
(when (fboundp 'ansi-color-compilation-filter)
989+
(add-hook 'compilation-filter-hook #'ansi-color-compilation-filter nil t))
990+
(setq-local compilation-error-regexp-alist '(swift-testing)))
991+
992+
(defvar swift-mode:original-compilation-process-setup-function nil
993+
"`compilation-process-setup-function' before `swift-mode:setup-swift-testing'.
994+
995+
It is called from `swift-mode:compilation-process-setup-function'.")
996+
997+
(defun swift-mode:swift-testing-compilation-process-setup-function ()
998+
"`compilation-process-setup-function' for Swift Testing.
999+
1000+
Call original `compilation-process-setup-function' and prepare *compilation*
1001+
buffer.
1002+
1003+
See also `swift-mode:setup-swift-testing-buffer'."
1004+
(when swift-mode:original-compilation-process-setup-function
1005+
(funcall swift-mode:original-compilation-process-setup-function))
1006+
(when (string-match-p swift-mode:swift-testing-command-regexp
1007+
(car compilation-arguments))
1008+
(swift-mode:setup-swift-testing-buffer)))
1009+
1010+
(defun swift-mode:find-test-sources (project-directory target)
1011+
"Return a list of the absolute paths of test sources.
1012+
1013+
The manifest file is searched from the PROJECT-DIRECTORY, defaults to
1014+
`default-directory', or its ancestors.
1015+
1016+
If TARGET is non-nil, return only sources of that target."
1017+
(let* ((description (swift-mode:describe-package project-directory))
1018+
(targets (cdr (assoc 'targets description)))
1019+
(test-targets (seq-filter
1020+
(lambda (module)
1021+
(and (equal "test" (cdr (assoc 'type module)))
1022+
(or (null target)
1023+
(equal target (cdr (assoc 'name module))))))
1024+
targets))
1025+
(project-path (cdr (assoc 'path description)))
1026+
target-path)
1027+
(seq-mapcat
1028+
(lambda (target)
1029+
(setq target-path
1030+
(expand-file-name (cdr (assoc 'path target)) project-path))
1031+
(mapcar (lambda (source)
1032+
(expand-file-name source target-path))
1033+
(cdr (assoc 'sources target))))
1034+
test-targets)))
1035+
1036+
(defun swift-mode:resolve-swift-test-file (file)
1037+
"Return full path of Swift Testing FILE in the project if any.
1038+
1039+
If FILE is an absolute path, return it as is, even if it doesn't exist.
1040+
1041+
If FILE doesn't exist in the project, return nil."
1042+
(if (file-name-absolute-p file)
1043+
(list file)
1044+
(when (null swift-mode:compilation-swift-files)
1045+
(setq-local swift-mode:compilation-swift-files
1046+
(make-hash-table :test 'equal))
1047+
(dolist (path (swift-mode:find-test-sources
1048+
(or compilation-directory default-directory)
1049+
;; TODO
1050+
nil))
1051+
(puthash (file-name-nondirectory path)
1052+
path
1053+
swift-mode:compilation-swift-files)))
1054+
(let ((path (gethash (file-name-nondirectory file)
1055+
swift-mode:compilation-swift-files)))
1056+
(and path (list path)))))
1057+
1058+
(defun swift-mode:setup-swift-testing ()
1059+
"Setup `compilation-process-setup-function' for Swift Testing.
1060+
1061+
Save original `compilation-process-setup-function' and set
1062+
`compilation-process-setup-function' to
1063+
`swift-mode:swift-testing-compilation-process-setup-function'.
1064+
1065+
Also add an entry to `compilation-error-regexp-alist-alist'."
1066+
(unless swift-mode:original-compilation-process-setup-function
1067+
(setq swift-mode:original-compilation-process-setup-function
1068+
(or compilation-process-setup-function #'ignore))
1069+
(setq compilation-process-setup-function
1070+
#'swift-mode:swift-testing-compilation-process-setup-function)
1071+
(add-to-list 'compilation-error-regexp-alist-alist
1072+
`(swift-testing
1073+
,(rx bol
1074+
(zero-or-one (seq (* not-newline) (any " \t")))
1075+
(group
1076+
(group (+ (not (any " \t\n"))) ".swift")
1077+
":"
1078+
(group (+ digit))
1079+
(zero-or-one
1080+
":"
1081+
(group (+ digit))))
1082+
": ")
1083+
;; filename
1084+
,(lambda ()
1085+
(save-match-data
1086+
(funcall swift-mode:resolve-swift-test-file-function
1087+
(match-string 2))))
1088+
;; line
1089+
3
1090+
;; column
1091+
4
1092+
;; type
1093+
nil
1094+
;; hyperlink
1095+
1))))
1096+
9621097
(provide 'swift-mode-repl)
9631098

9641099
;;; swift-mode-repl.el ends here

swift-mode.el

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@ Signal `scan-error' if it hits opening parentheses."
239239
(when (equal (with-current-buffer (current-buffer) major-mode)
240240
'swift-mode)
241241
(swift-mode:current-defun-name))))
242-
(setq-local add-log-current-defun-function #'swift-mode:current-defun-name))
242+
(setq-local add-log-current-defun-function #'swift-mode:current-defun-name)
243+
244+
(swift-mode:setup-swift-testing))
243245

244246
;;;###autoload (add-to-list 'auto-mode-alist
245247
;;;###autoload '("\\.swift\\(interface\\)?\\'" . swift-mode))

0 commit comments

Comments
 (0)