Commands.swift 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. /// A set of menus to be displayed in a menu bar.
  2. public struct Commands {
  3. /// Represents an empty menu bar.
  4. public static var empty: Commands {
  5. Commands(menus: [])
  6. }
  7. var menus: [CommandMenu]
  8. init(menus: [CommandMenu]) {
  9. self.menus = menus
  10. }
  11. /// Overlays `newCommands` onto `self`.
  12. ///
  13. /// If top-level menus in `newCommands` and `self` have conflicting names,
  14. /// the menus get merged, with the items from `self`'s menu first, followed
  15. /// by the items from `newCommands`'s menus.
  16. ///
  17. /// - Parameter newCommands: The commands to overlay.
  18. /// - Returns: The overlayed commands.
  19. public consuming func overlayed(with newCommands: Commands) -> Commands {
  20. var newMenusByName: [String: Int] = [:]
  21. for (i, menu) in newCommands.menus.enumerated() {
  22. newMenusByName[menu.name] = i
  23. }
  24. for (i, menu) in menus.enumerated() {
  25. guard let newMenuIndex = newMenusByName[menu.name] else {
  26. continue
  27. }
  28. menus[i] = CommandMenu(
  29. name: menu.name,
  30. content: menu.content + newCommands.menus[newMenuIndex].content
  31. )
  32. }
  33. let existingMenuNames = Set(menus.map(\.name))
  34. for newMenu in newCommands.menus {
  35. guard !existingMenuNames.contains(newMenu.name) else {
  36. continue
  37. }
  38. menus.append(newMenu)
  39. }
  40. return self
  41. }
  42. /// Resolves the menus to a representation used by backends.
  43. @MainActor
  44. func resolve() -> [ResolvedMenu.Submenu] {
  45. menus.map { menu in
  46. menu.resolve()
  47. }
  48. }
  49. }