Skip to content

Commit 560242d

Browse files
msanderstaku0
authored andcommitted
Add support for choosing scheme when building/running iOS projects
* Filter `xcodebuild list` stderr output to avoid corrupting JSON * Simplify call-process &c. by moving destination out of call site * Address PR feedback
1 parent abf3426 commit 560242d

File tree

1 file changed

+67
-12
lines changed

1 file changed

+67
-12
lines changed

swift-mode-repl.el

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
118121
This function quotes elements appropriately."
@@ -234,7 +237,13 @@ then unquoted.
234237
ARGS 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.
394404
DEVICE-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.
413446
Typically, 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.
461496
Build 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'
463498
or 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'
671717
or 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

Comments
 (0)