From 68ffa6c5e49eff0bf83b56c28093220eafd07214 Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Wed, 22 Oct 2025 03:35:42 +0200 Subject: [PATCH] tart set: support optional "pt" and "px" units for "--display" argument (#1155) * tart set: support optional "pt" and "px" units for "--display" argument * Don't forget to update "unit" too --- Sources/tart/Commands/Set.swift | 17 +++++++++++++++-- Sources/tart/Platform/Darwin.swift | 2 +- Sources/tart/VMConfig.swift | 14 ++++++++++++-- Tests/TartTests/VMConfigTests.swift | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 Tests/TartTests/VMConfigTests.swift diff --git a/Sources/tart/Commands/Set.swift b/Sources/tart/Commands/Set.swift index fbb55d6..384fda8 100644 --- a/Sources/tart/Commands/Set.swift +++ b/Sources/tart/Commands/Set.swift @@ -14,7 +14,7 @@ struct Set: AsyncParsableCommand { @Option(help: "VM memory size in megabytes") var memory: UInt64? - @Option(help: "VM display resolution in a format of x. For example, 1200x800") + @Option(help: "VM display resolution in a format of WIDTHxHEIGHT[pt|px]. For example, 1200x800, 1200x800pt or 1920x1080px. Units are treated as hints and default to \"pt\" (points) for macOS VMs and \"px\" (pixels) for Linux VMs when not specified.") var display: VMDisplayConfig? @Flag(inversion: .prefixedNo, help: ArgumentHelp("Whether to automatically reconfigure the VM's display to fit the window")) @@ -56,6 +56,7 @@ struct Set: AsyncParsableCommand { if (display.height > 0) { vmConfig.display.height = display.height } + vmConfig.display.unit = display.unit } vmConfig.displayRefit = displayRefit @@ -88,12 +89,24 @@ struct Set: AsyncParsableCommand { extension VMDisplayConfig: ExpressibleByArgument { public init(argument: String) { + var argument = argument + var unit: Unit? = nil + + if argument.hasSuffix(Unit.pixel.rawValue) { + argument = String(argument.dropLast(Unit.pixel.rawValue.count)) + unit = Unit.pixel + } else if argument.hasSuffix(Unit.point.rawValue) { + argument = String(argument.dropLast(Unit.point.rawValue.count)) + unit = Unit.point + } + let parts = argument.components(separatedBy: "x").map { Int($0) ?? 0 } self = VMDisplayConfig( width: parts[safe: 0] ?? 0, - height: parts[safe: 1] ?? 0 + height: parts[safe: 1] ?? 0, + unit: unit, ) } } diff --git a/Sources/tart/Platform/Darwin.swift b/Sources/tart/Platform/Darwin.swift index 2aeb2a7..dcdca09 100644 --- a/Sources/tart/Platform/Darwin.swift +++ b/Sources/tart/Platform/Darwin.swift @@ -82,7 +82,7 @@ struct UnsupportedHostOSError: Error, CustomStringConvertible { func graphicsDevice(vmConfig: VMConfig) -> VZGraphicsDeviceConfiguration { let result = VZMacGraphicsDeviceConfiguration() - if let hostMainScreen = NSScreen.main { + if (vmConfig.display.unit ?? .point) == .point, let hostMainScreen = NSScreen.main { let vmScreenSize = NSSize(width: vmConfig.display.width, height: vmConfig.display.height) result.displays = [ VZMacGraphicsDisplayConfiguration(for: hostMainScreen, sizeInPoints: vmScreenSize) diff --git a/Sources/tart/VMConfig.swift b/Sources/tart/VMConfig.swift index 198cb24..c6e9ba9 100644 --- a/Sources/tart/VMConfig.swift +++ b/Sources/tart/VMConfig.swift @@ -32,14 +32,24 @@ enum CodingKeys: String, CodingKey { case hardwareModel } -struct VMDisplayConfig: Codable { +struct VMDisplayConfig: Codable, Equatable { + enum Unit: String, Codable { + case point = "pt" + case pixel = "px" + } + var width: Int = 1024 var height: Int = 768 + var unit: Unit? } extension VMDisplayConfig: CustomStringConvertible { var description: String { - "\(width)x\(height)" + if let unit { + "\(width)x\(height)\(unit.rawValue)" + } else { + "\(width)x\(height)" + } } } diff --git a/Tests/TartTests/VMConfigTests.swift b/Tests/TartTests/VMConfigTests.swift new file mode 100644 index 0000000..34fb901 --- /dev/null +++ b/Tests/TartTests/VMConfigTests.swift @@ -0,0 +1,18 @@ +import XCTest +@testable import tart + +final class VMConfigTests: XCTestCase { + func testVMDisplayConfig() throws { + // Defaults units (points) + var vmDisplayConfig = VMDisplayConfig.init(argument: "1234x5678") + XCTAssertEqual(VMDisplayConfig(width: 1234, height: 5678, unit: nil), vmDisplayConfig) + + // Explicit units (points) + vmDisplayConfig = VMDisplayConfig.init(argument: "1234x5678pt") + XCTAssertEqual(VMDisplayConfig(width: 1234, height: 5678, unit: .point), vmDisplayConfig) + + // Explicit units (pixels) + vmDisplayConfig = VMDisplayConfig.init(argument: "1234x5678px") + XCTAssertEqual(VMDisplayConfig(width: 1234, height: 5678, unit: .pixel), vmDisplayConfig) + } +}