@@ -113,6 +113,9 @@ otherwise.")
113113(defvar swift-mode:ios-simulator-device-identifier nil
114114 " Device identifier of iOS simulator for building/debugging." )
115115
116+ (defvar swift-mode:ios-project-scheme nil
117+ " Scheme to use in Xcode project for building/debugging." )
118+
116119(defun swift-mode:command-list-to-string (cmd )
117120 " Concatenate the CMD unless it is a string.
118121This function quotes elements appropriately."
@@ -234,7 +237,13 @@ then unquoted.
234237ARGS are rest arguments, appended to the argument list."
235238 (with-temp-buffer
236239 (unless (zerop
237- (apply 'swift-mode:call-process executable args))
240+ (swift-mode:do-call-process executable
241+ nil
242+ ; ; Disregard stderr output, as it
243+ ; ; corrupts JSON.
244+ (list t nil )
245+ nil
246+ args))
238247 (error " %s : %s " " Cannot invoke executable" (buffer-string )))
239248 (goto-char (point-min ))
240249 (json-read )))
@@ -309,7 +318,7 @@ Return a directory path if found. Return nil otherwise."
309318 'swift-mode:swift-project-directory-p directory))
310319
311320(defun swift-mode:read-project-directory ()
312- " Read a project direcotry from the minibuffer."
321+ " Read a project directory from the minibuffer."
313322 (expand-file-name (read-directory-name " Project directory: " nil nil t )))
314323
315324(defun swift-mode:ensure-swift-project-directory (project-directory )
@@ -389,6 +398,7 @@ or its ancestors."
389398 (widget-choose " Choose a device" items)))
390399
391400(defun swift-mode:read-xcode-build-settings (project-directory
401+ scheme
392402 device-identifier )
393403 " Read Xcode build settings in PROJECT-DIRECTORY.
394404DEVICE-IDENTIFIER is used as the destination parameter for xcodebuild."
@@ -400,6 +410,7 @@ DEVICE-IDENTIFIER is used as the destination parameter for xcodebuild."
400410 " -destination"
401411 (concat " platform=iOS Simulator,id=" device-identifier)
402412 " -sdk" " iphonesimulator"
413+ " -scheme" scheme
403414 " -showBuildSettings" ))
404415 (error " %s %s " " Cannot read Xcode build settings" (buffer-string ))))
405416 (goto-char (point-min ))
@@ -408,6 +419,28 @@ DEVICE-IDENTIFIER is used as the destination parameter for xcodebuild."
408419 (push (cons (match-string 1 ) (match-string 2 )) settings))
409420 settings)))
410421
422+ (defun swift-mode:xcodebuild-list (project-directory )
423+ " Returns the contents of `xcodebuild -list' as JSON."
424+ (let ((default-directory project-directory)
425+ (json-array-type 'list ))
426+ (swift-mode:call-process-to-json
427+ swift-mode:xcodebuild-executable
428+ " -list"
429+ " -json" )))
430+
431+ (defun swift-mode:read-project-scheme (project-directory )
432+ " Reads and prompts for a project's scheme in the minibuffer."
433+ (let* ((json (swift-mode:xcodebuild-list project-directory))
434+ (project (cdr (assoc 'project json)))
435+ (schemes (cdr (assoc 'schemes project)))
436+ (choices (seq-map
437+ (lambda (scheme ) (cons scheme scheme))
438+ schemes)))
439+ (pcase (length schemes)
440+ (1 (car schemes))
441+ (0 nil )
442+ (_ (widget-choose " Choose a scheme" choices)))))
443+
411444(defun swift-mode:locate-xcode ()
412445 " Return the developer path in Xcode.app.
413446Typically, it is /Applications/Xcode.app/Contents/Developer."
@@ -456,13 +489,18 @@ An list ARGS are appended for builder command line arguments."
456489 (progress-reporter-done progress-reporter))))
457490
458491;;;### autoload
459- (defun swift-mode:build-ios-app (&optional project-directory device-identifier )
460- " Build a iOS app in the PROJECT-DIRECTORY.
492+ (defun swift-mode:build-ios-app (&optional project-directory
493+ device-identifier
494+ scheme )
495+ " Build an iOS app in the PROJECT-DIRECTORY for the given SCHEME.
461496Build it for iOS simulator device DEVICE-IDENTIFIER.
462- If PROJECT-DIRECTORY is nil or omited , it is searched from `default-directory'
497+ If PROJECT-DIRECTORY is nil or omitted , it is searched from `default-directory'
463498or its ancestors.
464- If DEVICE-IDENTIFIER is nil or omited,
465- the value of `swift-mode:ios-simulator-device-identifier' is used."
499+ If DEVICE-IDENTIFIER is nil or omitted,
500+ the value of `swift-mode:ios-simulator-device-identifier' is used.
501+ If SCHEME is nil or omitted,
502+ the value of `swift-mode:ios-project-scheme' is used.
503+ "
466504 (interactive
467505 (list
468506 (if current-prefix-arg
@@ -479,6 +517,11 @@ the value of `swift-mode:ios-simulator-device-identifier' is used."
479517 swift-mode:ios-simulator-device-identifier
480518 (swift-mode:read-ios-simulator-device-identifier))))
481519 (setq swift-mode:ios-simulator-device-identifier device-identifier)
520+ (unless scheme
521+ (setq scheme (or
522+ swift-mode:ios-project-scheme
523+ (swift-mode:read-project-scheme project-directory))))
524+ (setq swift-mode:ios-project-scheme scheme)
482525
483526 (with-current-buffer (get-buffer-create " *swift-mode:compilation*" )
484527 (fundamental-mode )
@@ -490,6 +533,7 @@ the value of `swift-mode:ios-simulator-device-identifier' is used."
490533 (swift-mode:call-process
491534 swift-mode:xcodebuild-executable
492535 " -configuration" " Debug"
536+ " -scheme" scheme
493537 " -destination"
494538 (concat " platform=iOS Simulator,id=" device-identifier)
495539 " -sdk" " iphonesimulator" )))
@@ -665,11 +709,14 @@ PROCESS-IDENTIFIER is the process ID."
665709 (search-forward expected-output nil t )))
666710
667711;;;### autoload
668- (defun swift-mode:debug-ios-app (&optional project-directory device-identifier )
669- " Run debugger on an iOS app in the PROJECT-DIRECTORY.
670- If PROJECT-DIRECTORY is nil or omited, it is searched from `default-directory'
712+ (defun swift-mode:debug-ios-app (&optional project-directory
713+ device-identifier
714+ scheme )
715+ " Run debugger on an iOS app in the PROJECT-DIRECTORY for the given SCHEME.
716+ If PROJECT-DIRECTORY is nil or omitted, it is searched from `default-directory'
671717or its ancestors.
672- DEVICE-IDENTIFIER is the device identifier of the iOS simulator."
718+ DEVICE-IDENTIFIER is the device identifier of the iOS simulator.
719+ SCHEME is the name of the project scheme in Xcode."
673720 (interactive
674721 (list
675722 (if current-prefix-arg
@@ -686,9 +733,15 @@ DEVICE-IDENTIFIER is the device identifier of the iOS simulator."
686733 swift-mode:ios-simulator-device-identifier
687734 (swift-mode:read-ios-simulator-device-identifier))))
688735 (setq swift-mode:ios-simulator-device-identifier device-identifier)
736+ (unless scheme
737+ (setq scheme (or
738+ swift-mode:ios-project-scheme
739+ (swift-mode:read-project-scheme project-directory))))
740+ (setq swift-mode:ios-project-scheme scheme)
689741 (let* ((build-settings
690742 (swift-mode:read-xcode-build-settings
691743 project-directory
744+ scheme
692745 device-identifier))
693746 (codesigning-folder-path
694747 (cdr (assoc " CODESIGNING_FOLDER_PATH" build-settings)))
@@ -698,7 +751,9 @@ DEVICE-IDENTIFIER is the device identifier of the iOS simulator."
698751 (error " Cannot get codesigning folder path " ))
699752 (unless product-bundle-identifier
700753 (error " Cannot get product bundle identifier " ))
701- (swift-mode:build-ios-app project-directory device-identifier)
754+ (swift-mode:build-ios-app project-directory
755+ device-identifier
756+ scheme)
702757
703758 (let* ((devices (swift-mode:list-ios-simulator-devices))
704759 (target-device
0 commit comments