From 35b6c7bbe7f769a87500ef035e55c5b6d6104e37 Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Sun, 19 May 2024 12:03:09 +0200 Subject: [PATCH] Implement trigger-binding command https://github.com/nikitabobko/AeroSpace/issues/215 --- Sources/AppBundle/TrayMenuModel.swift | 1 + Sources/AppBundle/command/Command.swift | 5 +++ .../command/TriggerBindingCommand.swift | 20 +++++++++++ .../command/other/parseCommand.swift | 2 ++ Sources/AppBundle/config/Config.swift | 1 - Sources/AppBundle/config/HotkeyBinding.swift | 1 + .../cmdArgs/TriggerBindingCmdArgs.swift | 33 +++++++++++++++++++ Sources/Common/cmdArgs/other/CmdKind.swift | 1 + .../Common/cmdArgs/other/parseCmdArgs.swift | 2 ++ Sources/Common/util/commonUtil.swift | 1 + docs/aerospace-trigger-binding.adoc | 29 ++++++++++++++++ docs/commands.adoc | 7 ++++ 12 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 Sources/AppBundle/command/TriggerBindingCommand.swift create mode 100644 Sources/Common/cmdArgs/TriggerBindingCmdArgs.swift create mode 100644 docs/aerospace-trigger-binding.adoc diff --git a/Sources/AppBundle/TrayMenuModel.swift b/Sources/AppBundle/TrayMenuModel.swift index 98160880..cfb06157 100644 --- a/Sources/AppBundle/TrayMenuModel.swift +++ b/Sources/AppBundle/TrayMenuModel.swift @@ -1,4 +1,5 @@ import AppKit +import Common public class TrayMenuModel: ObservableObject { public static let shared = TrayMenuModel() diff --git a/Sources/AppBundle/command/Command.swift b/Sources/AppBundle/command/Command.swift index 889b3746..7be6c43b 100644 --- a/Sources/AppBundle/command/Command.swift +++ b/Sources/AppBundle/command/Command.swift @@ -97,3 +97,8 @@ extension CommandSubject { } } } + +func failCmdWithMsg(_ state: CommandMutableState, _ msg: String) -> Bool { + state.stderr.append(msg) + return false +} diff --git a/Sources/AppBundle/command/TriggerBindingCommand.swift b/Sources/AppBundle/command/TriggerBindingCommand.swift new file mode 100644 index 00000000..a1ba5a82 --- /dev/null +++ b/Sources/AppBundle/command/TriggerBindingCommand.swift @@ -0,0 +1,20 @@ +import AppKit +import Common + +struct TriggerBindingCommand: Command { + let args: TriggerBindingCmdArgs + + func _run(_ state: CommandMutableState, stdin: String) -> Bool { + check(Thread.current.isMainThread) + return if let mode = config.modes[args.mode] { + if let binding = mode.bindings[args.binding.val] { + refreshSession(forceFocus: true) { binding.commands.run(state) } + } else { + failCmdWithMsg(state, "Binding '\(args.binding)' is not presented in mode '\(args.mode)'") + } + } else { + failCmdWithMsg(state, "Mode '\(args.mode)' doesn't exist. " + + "Available modes: \(config.modes.keys.joined(separator: ","))") + } + } +} diff --git a/Sources/AppBundle/command/other/parseCommand.swift b/Sources/AppBundle/command/other/parseCommand.swift index 5ea16c60..ae399f83 100644 --- a/Sources/AppBundle/command/other/parseCommand.swift +++ b/Sources/AppBundle/command/other/parseCommand.swift @@ -75,6 +75,8 @@ extension CmdArgs { command = SplitCommand(args: self as! SplitCmdArgs) case .serverVersionInternalCommand: command = ServerVersionInternalCommandCommand() + case .triggerBinding: + command = TriggerBindingCommand(args: self as! TriggerBindingCmdArgs) case .workspace: command = WorkspaceCommand(args: self as! WorkspaceCmdArgs) case .workspaceBackAndForth: diff --git a/Sources/AppBundle/config/Config.swift b/Sources/AppBundle/config/Config.swift index b3335670..463a9c60 100644 --- a/Sources/AppBundle/config/Config.swift +++ b/Sources/AppBundle/config/Config.swift @@ -2,7 +2,6 @@ import AppKit import HotKey import Common -let mainModeId = "main" var defaultConfigUrl: URL { if isUnitTest { var url = URL(filePath: #file) diff --git a/Sources/AppBundle/config/HotkeyBinding.swift b/Sources/AppBundle/config/HotkeyBinding.swift index f148b405..18aa3274 100644 --- a/Sources/AppBundle/config/HotkeyBinding.swift +++ b/Sources/AppBundle/config/HotkeyBinding.swift @@ -1,4 +1,5 @@ import AppKit +import Common import Foundation import HotKey import TOMLKit diff --git a/Sources/Common/cmdArgs/TriggerBindingCmdArgs.swift b/Sources/Common/cmdArgs/TriggerBindingCmdArgs.swift new file mode 100644 index 00000000..4d035dd2 --- /dev/null +++ b/Sources/Common/cmdArgs/TriggerBindingCmdArgs.swift @@ -0,0 +1,33 @@ +public struct TriggerBindingCmdArgs: RawCmdArgs, CmdArgs { + public let rawArgs: EquatableNoop<[String]> + public static let parser: CmdParser = cmdParser( + kind: .triggerBinding, + allowInConfig: true, + help: """ + USAGE: trigger-binding [-h|--help] --mode + + OPTIONS: + -h, --help Print help + --mode Mode to search in + + ARGUMENTS: + Binding to trigger + """, + options: [ + "--mode": singleValueOption(\._mode, "", { $0 }) + ], + arguments: [newArgParser(\.binding, { arg, _ in .success(arg) }, mandatoryArgPlaceholder: "")] + ) + + public var _mode: String? = nil + public var binding: Lateinit = .uninitialized +} + +public extension TriggerBindingCmdArgs { + var mode: String { _mode! } +} + +public func parseTriggerBindingCmdArgs(_ args: [String]) -> ParsedCmd { + parseRawCmdArgs(TriggerBindingCmdArgs(rawArgs: .init(args)), args) + .filter("--mode flag is mandatory") { $0._mode != nil } +} diff --git a/Sources/Common/cmdArgs/other/CmdKind.swift b/Sources/Common/cmdArgs/other/CmdKind.swift index c9129464..4e4cb3b1 100644 --- a/Sources/Common/cmdArgs/other/CmdKind.swift +++ b/Sources/Common/cmdArgs/other/CmdKind.swift @@ -26,6 +26,7 @@ public enum CmdKind: String, CaseIterable, Equatable { case reloadConfig = "reload-config" case resize case split + case triggerBinding = "trigger-binding" case workspace case workspaceBackAndForth = "workspace-back-and-forth" diff --git a/Sources/Common/cmdArgs/other/parseCmdArgs.swift b/Sources/Common/cmdArgs/other/parseCmdArgs.swift index b9b9e637..2846e539 100644 --- a/Sources/Common/cmdArgs/other/parseCmdArgs.swift +++ b/Sources/Common/cmdArgs/other/parseCmdArgs.swift @@ -76,6 +76,8 @@ private func initSubcommands() -> [String: any SubCommandParserProtocol] { if isServer { result[kind.rawValue] = defaultSubCommandParser(ServerVersionInternalCommandCmdArgs.init) } + case .triggerBinding: + result[kind.rawValue] = SubCommandParser(parseTriggerBindingCmdArgs) case .workspace: result[kind.rawValue] = SubCommandParser(parseWorkspaceCmdArgs) case .workspaceBackAndForth: diff --git a/Sources/Common/util/commonUtil.swift b/Sources/Common/util/commonUtil.swift index f5860468..61d54eed 100644 --- a/Sources/Common/util/commonUtil.swift +++ b/Sources/Common/util/commonUtil.swift @@ -1,6 +1,7 @@ import Foundation import AppKit +public let mainModeId = "main" private var recursionDetectorDuringFailure: Bool = false public func errorT( diff --git a/docs/aerospace-trigger-binding.adoc b/docs/aerospace-trigger-binding.adoc new file mode 100644 index 00000000..41694592 --- /dev/null +++ b/docs/aerospace-trigger-binding.adoc @@ -0,0 +1,29 @@ += aerospace-trigger-binding(1) +include::util/man-attributes.adoc[] +:manname: aerospace-trigger-binding +// tag::purpose[] +:manpurpose: Trigger AeroSpace binding as if it was pressed by user +// end::purpose[] + +== Synopsis +// tag::synopsis[] +aerospace trigger-binding [-h|--help] --mode +// end::synopsis[] + +== Description + +// tag::body[] +{manpurpose} + +include::util/conditional-options-header.adoc[] + +-h, --help:: Print help +--mode :: Mode to search `` in + +include::util/conditional-arguments-header.adoc[] + +:: Binding to trigger + +// end::body[] + +include::util/man-footer.adoc[] diff --git a/docs/commands.adoc b/docs/commands.adoc index 52d9c2bf..63a8e53f 100644 --- a/docs/commands.adoc +++ b/docs/commands.adoc @@ -144,6 +144,13 @@ include::aerospace-split.adoc[tags=synopsis] include::aerospace-split.adoc[tags=purpose] include::aerospace-split.adoc[tags=body] +== trigger-binding +---- +include::aerospace-trigger-binding.adoc[tags=synopsis] +---- +include::aerospace-trigger-binding.adoc[tags=purpose] +include::aerospace-trigger-binding.adoc[tags=body] + == workspace ---- include::aerospace-workspace.adoc[tags=synopsis]