-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Refactor #1
Changes from all commits
2496820
cf24ae9
2b8aa01
55ca837
1cdaeb2
e6d053d
e387f95
58e4746
1125e8c
20511b3
e7bd7ab
ca8781f
e8da38e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,3 +13,5 @@ DerivedData/ | |
|
|
||
| # SwiftLint Remote Config Cache | ||
| .swiftlint/RemoteConfigCache | ||
| .claude | ||
| MEGAREADME.md | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||||
| // swift-tools-version:5.3 | ||||||||
| // swift-tools-version:5.11 | ||||||||
|
|
||||||||
| import PackageDescription | ||||||||
|
|
||||||||
|
|
@@ -9,7 +9,10 @@ let package = Package( | |||||||
| .library( | ||||||||
| name: "BetterSwiftAX", | ||||||||
| targets: ["AccessibilityControl"] | ||||||||
| ), | ||||||||
| ) | ||||||||
| ], | ||||||||
| dependencies: [ | ||||||||
| .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0"), | ||||||||
|
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused dependency: The package declares a dependency on 🗑️ Option A: Remove unused dependency- dependencies: [
- .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0"),
- ],
+ dependencies: [],➕ Option B: Add to a target that needs it .target(
name: "AccessibilityControl",
- dependencies: ["CAccessibilityControl", "WindowControl"]
+ dependencies: ["CAccessibilityControl", "WindowControl", .product(name: "ArgumentParser", package: "swift-argument-parser")]
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| ], | ||||||||
| targets: [ | ||||||||
| .target( | ||||||||
|
|
@@ -25,6 +28,6 @@ let package = Package( | |||||||
| .target( | ||||||||
| name: "AccessibilityControl", | ||||||||
| dependencies: ["CAccessibilityControl", "WindowControl"] | ||||||||
| ), | ||||||||
| ) | ||||||||
| ] | ||||||||
| ) | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import ApplicationServices | ||
|
|
||
| extension Accessibility { | ||
| // https://developer.apple.com/documentation/applicationservices/carbon_accessibility/roles | ||
| public enum Role { | ||
| public static let application = kAXApplicationRole | ||
| public static let systemWide = kAXSystemWideRole | ||
| public static let window = kAXWindowRole | ||
| public static let sheet = kAXSheetRole | ||
| public static let drawer = kAXDrawerRole | ||
| public static let growArea = kAXGrowAreaRole | ||
| public static let image = kAXImageRole | ||
| public static let unknown = kAXUnknownRole | ||
| public static let button = kAXButtonRole | ||
| public static let radioButton = kAXRadioButtonRole | ||
| public static let checkBox = kAXCheckBoxRole | ||
| public static let popUpButton = kAXPopUpButtonRole | ||
| public static let menuButton = kAXMenuButtonRole | ||
| public static let tabGroup = kAXTabGroupRole | ||
| public static let table = kAXTableRole | ||
| public static let column = kAXColumnRole | ||
| public static let row = kAXRowRole | ||
| public static let outline = kAXOutlineRole | ||
| public static let browser = kAXBrowserRole | ||
| public static let scrollArea = kAXScrollAreaRole | ||
| public static let scrollBar = kAXScrollBarRole | ||
| public static let radioGroup = kAXRadioGroupRole | ||
| public static let list = kAXListRole | ||
| public static let group = kAXGroupRole | ||
| public static let valueIndicator = kAXValueIndicatorRole | ||
| public static let comboBox = kAXComboBoxRole | ||
| public static let slider = kAXSliderRole | ||
| public static let incrementor = kAXIncrementorRole | ||
| public static let busyIndicator = kAXBusyIndicatorRole | ||
| public static let progressIndicator = kAXProgressIndicatorRole | ||
| public static let relevanceIndicator = kAXRelevanceIndicatorRole | ||
| public static let toolbar = kAXToolbarRole | ||
| public static let disclosureTriangle = kAXDisclosureTriangleRole | ||
| public static let textField = kAXTextFieldRole | ||
| public static let textArea = kAXTextAreaRole | ||
| public static let staticText = kAXStaticTextRole | ||
| public static let menuBar = kAXMenuBarRole | ||
| public static let menuBarItem = kAXMenuBarItemRole | ||
| public static let menu = kAXMenuRole | ||
| public static let menuItem = kAXMenuItemRole | ||
| public static let splitGroup = kAXSplitGroupRole | ||
| public static let splitter = kAXSplitterRole | ||
| public static let colorWell = kAXColorWellRole | ||
| public static let timeField = kAXTimeFieldRole | ||
| public static let dateField = kAXDateFieldRole | ||
| public static let helpTag = kAXHelpTagRole | ||
| public static let matte = kAXMatteRole | ||
| public static let dockItem = kAXDockItemRole | ||
| public static let cell = kAXCellRole | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import ApplicationServices | ||
|
|
||
| extension Accessibility { | ||
| public enum Subrole { | ||
| public static let `switch` = kAXSwitchSubrole | ||
| public static let closeButton = kAXCloseButtonSubrole | ||
| public static let minimizeButton = kAXMinimizeButtonSubrole | ||
| public static let zoomButton = kAXZoomButtonSubrole | ||
| public static let toolbarButton = kAXToolbarButtonSubrole | ||
| public static let secureTextField = kAXSecureTextFieldSubrole | ||
| public static let tableRow = kAXTableRowSubrole | ||
| public static let outlineRow = kAXOutlineRowSubrole | ||
| public static let unknown = kAXUnknownSubrole | ||
| public static let standardWindow = kAXStandardWindowSubrole | ||
| public static let dialog = kAXDialogSubrole | ||
| public static let systemDialog = kAXSystemDialogSubrole | ||
| public static let floatingWindow = kAXFloatingWindowSubrole | ||
| public static let systemFloatingWindow = kAXSystemFloatingWindowSubrole | ||
| public static let incrementArrow = kAXIncrementArrowSubrole | ||
| public static let decrementArrow = kAXDecrementArrowSubrole | ||
| public static let incrementPage = kAXIncrementPageSubrole | ||
| public static let decrementPage = kAXDecrementPageSubrole | ||
| public static let sortButton = kAXSortButtonSubrole | ||
| public static let searchField = kAXSearchFieldSubrole | ||
| public static let applicationDockItem = kAXApplicationDockItemSubrole | ||
| public static let documentDockItem = kAXDocumentDockItemSubrole | ||
| public static let folderDockItem = kAXFolderDockItemSubrole | ||
| public static let minimizedWindowDockItem = kAXMinimizedWindowDockItemSubrole | ||
| public static let urlDockItem = kAXURLDockItemSubrole | ||
| public static let dockExtraDockItem = kAXDockExtraDockItemSubrole | ||
| public static let trashDockItem = kAXTrashDockItemSubrole | ||
| public static let processSwitcherList = kAXProcessSwitcherListSubrole | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,92 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import CoreFoundation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os.log | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private let log = OSLog(subsystem: "com.betterswiftax", category: "accessibility") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public extension Accessibility.Element { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var isValid: Bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (try? pid()) != nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var isFrameValid: Bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (try? self.frame()) != nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var isInViewport: Bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (try? self.frame()) != CGRect.null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+15
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🐛 Proposed fix var isInViewport: Bool {
- (try? self.frame()) != CGRect.null
+ guard let frame = try? self.frame() else { return false }
+ return frame != CGRect.null
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // - breadth-first, seems faster than dfs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // - default max complexity to 1,800; if i dump the complexity of the Messages app right now i get ~360. x10 that, should be plenty | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // - we can't turn `AXUIElement`s into e.g. `ObjectIdentifier`s and use that to track a set of seen elements and avoid cycles because | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // the objects aren't pooled; any given instance of `AXUIElement` in memory is "transient" and another may take its place | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func recursiveChildren(maxTraversalComplexity: Int = 3_600) -> AnySequence<Accessibility.Element> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // incremented for every element with children that we discover; not "depth" since it's a running tally | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var traversalComplexity = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return AnySequence(sequence(state: [self] as [Accessibility.Element]) { queue -> Accessibility.Element? in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| guard traversalComplexity < maxTraversalComplexity else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| os_log(.error, log: log, "HIT RECURSIVE TRAVERSAL COMPLEXITY LIMIT (%d > %d, queue count: %d), terminating early", traversalComplexity, maxTraversalComplexity, queue.count) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| guard !queue.isEmpty else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // queue is empty, we're done | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let elt = queue.removeFirst() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let children = try? elt.children() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defer { traversalComplexity += 1 } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queue.append(contentsOf: children) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return elt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func recursiveSelectedChildren() -> AnySequence<Accessibility.Element> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AnySequence(sequence(state: [self]) { queue -> Accessibility.Element? in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| guard !queue.isEmpty else { return nil } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let elt = queue.removeFirst() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let selectedChildren = try? elt.selectedChildren() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queue.append(contentsOf: selectedChildren) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return elt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Unlike 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func recursivelyFindChild(withID id: String) -> Accessibility.Element? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| recursiveChildren().lazy.first { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (try? $0.identifier()) == id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func setFrame(_ frame: CGRect) throws { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DispatchQueue.concurrentPerform(iterations: 2) { i in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch i { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 0: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try? self.position(assign: frame.origin) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 1: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try? self.size(assign: frame.size) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Both Option A: Remove `throws` (matches current behavior)- func setFrame(_ frame: CGRect) throws {
+ func setFrame(_ frame: CGRect) {Option B: Propagate errors sequentially func setFrame(_ frame: CGRect) throws {
- DispatchQueue.concurrentPerform(iterations: 2) { i in
- switch i {
- case 0:
- try? self.position(assign: frame.origin)
- case 1:
- try? self.size(assign: frame.size)
- default:
- break
- }
- }
+ try self.position(assign: frame.origin)
+ try self.size(assign: frame.size)
}📝 Committable suggestion
Suggested change
Suggested change
🧰 Tools🪛 SwiftLint (0.63.2)[Warning] 66-66: Magic numbers should be replaced by named constants (no_magic_numbers) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func closeWindow() throws { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| guard let closeButton = try? self.windowCloseButton() else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw AccessibilityError(.failure) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try closeButton.press() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public extension Accessibility.Element { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func firstChild(withRole role: KeyPath<Accessibility.Role.Type, String>) -> Accessibility.Element? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try? self.children().first { child in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (try? child.role()) == Accessibility.Role.self[keyPath: role] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Swift 5.11 release date tools version availability💡 Result:
swift-tools-version: 5.11: If you’re asking about Swift Package Manager tools version 5.11, it’s not tied to a stable “Swift 5.11” compiler release, and using newer tools versions inside Xcode can be confusing because Xcode uses its own embedded SwiftPM, which may not match an installed custom toolchain. [3]Sources:
[1] Swift.org — Swift 5.10 Released (Mar 5, 2024) (swift.org)
[2] Swift.org — Announcing Swift 6 (Sep 17, 2024) (swift.org)
[3] Swift Forums — discussion of 5.10/“5.11” development snapshots & Xcode SwiftPM behavior (Feb 2024) (forums.swift.org)
[4] Apple Developer — Xcode releases table showing Swift 6.0 with Xcode 16 (developer.apple.com)
Citations:
Remove swift-tools-version:5.11—this version does not exist.
Swift 5.11 was never released. Swift 5.10 (March 2024) was the final Swift 5.x release; the next version is Swift 6.0 (September 2024). "5.11" appeared only as a development snapshot identifier and is not available in any production Xcode or SwiftPM toolchain. Change to
swift-tools-version:5.10orswift-tools-version:6.0depending on your minimum Xcode requirement.🤖 Prompt for AI Agents