diff --git a/Sources/StreamDeck/Macros/SettingsMacros.swift b/Sources/StreamDeck/Macros/SettingsMacros.swift index 867597e..9c81983 100644 --- a/Sources/StreamDeck/Macros/SettingsMacros.swift +++ b/Sources/StreamDeck/Macros/SettingsMacros.swift @@ -17,6 +17,6 @@ public macro globalSetting(_ name: String, defaultValue value: T, ofType: T.T public macro environmentKey(_ name: String, defaultValue value: T, ofType: T.Type) = #externalMacro(module: "StreamDeckMacros", type: "EnvironmentMacro") @attached(accessor) -@attached(peer, names: prefixed(__Key_)) -public macro Entry() = #externalMacro(module: "StreamDeckMacros", type: "EntryMacro") +@attached(peer, names: arbitrary) +public macro Entry(_ name: String? = nil) = #externalMacro(module: "StreamDeckMacros", type: "EntryMacro") #endif diff --git a/Sources/StreamDeckMacros/EntryMacro.swift b/Sources/StreamDeckMacros/EntryMacro.swift index f65ea98..64f6431 100644 --- a/Sources/StreamDeckMacros/EntryMacro.swift +++ b/Sources/StreamDeckMacros/EntryMacro.swift @@ -27,6 +27,16 @@ struct EntryMacro { } } + static func identifier(of node: AttributeSyntax, or declaration: some DeclSyntaxProtocol) throws -> String { + // Check if the user specified a custom name for the key + if let arg = customKeyName(for: node) { + return arg + } else { + return try identifier(of: declaration) + } + } + + /// Return the identifier of a declaration. static func identifier(of declaration: some DeclSyntaxProtocol) throws -> String { guard let variableDecl = declaration.as(VariableDeclSyntax.self), let patternBinding = variableDecl.bindings.as(PatternBindingListSyntax.self)?.first?.as(PatternBindingSyntax.self), @@ -38,6 +48,7 @@ struct EntryMacro { return identifier } + /// Return the initializer of a declaration. static func initializer(of declaration: some DeclSyntaxProtocol) throws -> InitializerClauseSyntax { guard let variableDecl = declaration.as(VariableDeclSyntax.self), let patternBinding = variableDecl.bindings.as(PatternBindingListSyntax.self)?.first?.as(PatternBindingSyntax.self), @@ -50,6 +61,7 @@ struct EntryMacro { return initializer } + /// Return the type identifier the macro is in. static func extensionKey(of context: some MacroExpansionContext) throws -> KeyType { let extensionType = context.lexicalContext.first? .as(ExtensionDeclSyntax.self)?.extendedType @@ -65,6 +77,18 @@ struct EntryMacro { return key } + + /// Return the string value of the first argument of a node. + static func customKeyName(for node: AttributeSyntax) -> String? { + guard + let exprList = node.arguments?.as(LabeledExprListSyntax.self), + let stringExpr = exprList.first?.expression.as(StringLiteralExprSyntax.self) + else { + return nil + } + + return stringExpr.representedLiteralValue + } } @@ -72,7 +96,7 @@ extension EntryMacro: AccessorMacro { static func expansion(of node: AttributeSyntax, providingAccessorsOf declaration: some DeclSyntaxProtocol, in context: some MacroExpansionContext ) throws -> [AccessorDeclSyntax] { - let identifier = try identifier(of: declaration) + let identifier = try identifier(of: node, or: declaration) let settingName = "__Key_\(identifier)" @@ -84,13 +108,15 @@ extension EntryMacro: AccessorMacro { } extension EntryMacro: PeerMacro { + static func expansion(of node: AttributeSyntax, providingPeersOf declaration: some DeclSyntaxProtocol, in context: some MacroExpansionContext) throws -> [DeclSyntax] { - let identifier = try identifier(of: declaration) + let keyIdentifier = try identifier(of: node, or: declaration) + let initializer = try initializer(of: declaration) let keyType = try extensionKey(of: context) - let settingName = "__Key_\(identifier)" + let settingName = "__Key_\(keyIdentifier)" // Create the inheritance token let globSetKey = InheritanceClauseSyntax { @@ -101,7 +127,7 @@ extension EntryMacro: PeerMacro { let settingStruct = try StructDeclSyntax(name: "\(raw: settingName)") { // Create an override for the key name - try VariableDeclSyntax("static let name = \"\(raw: settingName)\"") + try VariableDeclSyntax("static let name = \"\(raw: keyIdentifier)\"") VariableDeclSyntax(bindingSpecifier: "static let") { PatternBindingSyntax(