Repository: swift-server/swiftly (swift)

Issue:
Print currently in-use toolchain if no arguments are provided to `use`
To retrieve the currently in-use toolchain, users currently need to either visually parse the output of `swiftly list` or pipe it to `grep use`. To make this a bit easier, swiftly should print the in use toolchain if no arguments are provided to `use`.

e.g.
```
$ swiftly use
main-snapshot-2023-09-22 (in use)
```

Pull request:
Closes #70

Patch:
diff --git a/Sources/Swiftly/Use.swift b/Sources/Swiftly/Use.swift
index 72d02069..acfdb36c 100644
--- a/Sources/Swiftly/Use.swift
+++ b/Sources/Swiftly/Use.swift
@@ -3,13 +3,17 @@ import SwiftlyCore
 
 internal struct Use: SwiftlyCommand {
     public static var configuration = CommandConfiguration(
-        abstract: "Set the active toolchain."
+        abstract: "Set the active toolchain. If no toolchain is provided, print the currently in-use toolchain, if any."
     )
 
     @Argument(help: ArgumentHelp(
         "The toolchain to use.",
         discussion: """
 
+        If no toolchain is provided, the currently in-use toolchain will be printed, if any:
+
+            $ swiftly use
+
         The string "latest" can be provided to use the most recent stable version release:
 
             $ swiftly use latest
@@ -32,18 +36,26 @@ internal struct Use: SwiftlyCommand {
         Likewise, the latest snapshot associated with a given development branch can be \
         used by omitting the date:
 
-            $ swiftly install 5.7-snapshot
-            $ swiftly install main-snapshot
+            $ swiftly use 5.7-snapshot
+            $ swiftly use main-snapshot
         """
     ))
-    var toolchain: String
+    var toolchain: String?
 
     internal mutating func run() async throws {
-        let selector = try ToolchainSelector(parsing: self.toolchain)
         var config = try Config.load()
 
+        guard let toolchain = self.toolchain else {
+            if let inUse = config.inUse {
+                SwiftlyCore.print("\(inUse) (in use)")
+            }
+            return
+        }
+
+        let selector = try ToolchainSelector(parsing: toolchain)
+
         guard let toolchain = config.listInstalledToolchains(selector: selector).max() else {
-            SwiftlyCore.print("No installed toolchains match \"\(self.toolchain)\"")
+            SwiftlyCore.print("No installed toolchains match \"\(toolchain)\"")
             return
         }
 


Test patch:
diff --git a/Tests/SwiftlyTests/UseTests.swift b/Tests/SwiftlyTests/UseTests.swift
index a3815edd..5f962933 100644
--- a/Tests/SwiftlyTests/UseTests.swift
+++ b/Tests/SwiftlyTests/UseTests.swift
@@ -306,4 +306,24 @@ final class UseTests: SwiftlyTests {
             XCTAssertEqual(yConfig.inUse, toolchain)
         }
     }
+
+    /// Tests that running a use command without an argument prints the currently in-use toolchain.
+    func testPrintInUse() async throws {
+        let toolchains = [
+            Self.newStable,
+            Self.newMainSnapshot,
+            Self.newReleaseSnapshot,
+        ]
+        try await self.withMockedHome(homeName: Self.homeName, toolchains: Set(toolchains)) {
+            for toolchain in toolchains {
+                var use = try self.parseCommand(Use.self, ["use", toolchain.name])
+                try await use.run()
+
+                var useEmpty = try self.parseCommand(Use.self, ["use"])
+                let output = try await useEmpty.runWithMockedIO()
+
+                XCTAssert(output.contains(where: { $0.contains(String(describing: toolchain)) }))
+            }
+        }
+    }
 }