Skip to content

Commit

Permalink
Draft implementation for layout command
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitabobko committed Sep 17, 2023
1 parent 73647e4 commit 5180eb8
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 23 deletions.
4 changes: 2 additions & 2 deletions config-examples/default-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ alt-enter = 'exec_and_forget open /System/Applications/Utilities/Terminal.app'

alt-shift-quote = 'focus child'
alt-quote = 'focus parent'
# alt-slash = 'layout h_list v_list'
# alt-comma = 'layout h_accordion v_accordion'
alt-slash = 'layout h_list v_list'
alt-comma = 'layout h_accordion v_accordion'

# todo focus floating binding

Expand Down
10 changes: 4 additions & 6 deletions config-examples/i3-like-config-example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ alt-shift-l = 'move_through right'

# alt-f = 'fullscreen' # todo support fullscreen command?

# todo support layout parsing
#alt-s = 'layout v_accordion' # 'layout stacking' in i3
#alt-w = 'layout h_accordion' # 'layout tabbed' in i3
#alt-e = 'layout h_list v_list' # 'layout toggle list' in i3
alt-s = 'layout v_accordion' # 'layout stacking' in i3
alt-w = 'layout h_accordion' # 'layout tabbed' in i3
alt-e = 'layout h_list v_list' # 'layout toggle list' in i3

#todo support parsing
#alt-shift-space = 'layout floating tiling' # 'floating toggle' in i3
alt-shift-space = 'layout floating tiling' # 'floating toggle' in i3

# Not supported, because this command is redundant in AeroSpace mental model.
# Floating windows are part of the tree from the perspective of 'focus' command.
Expand Down
69 changes: 60 additions & 9 deletions src/command/LayoutCommand.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,69 @@
/// Syntax:
/// layout (main|h_accordion|v_accordion|h_list|v_list|floating|tiling)...
struct LayoutCommand: Command {
let toggleTo: [Layout]
enum Layout {
case main
case h_accordion
case v_accordion
case h_list
case v_list
case floating
let toggleBetween: [Layout]
enum Layout: String {
//case main // todo drop?
case h_accordion, v_accordion, h_list, v_list
case floating, tiling
}

init?(toggleBetween: [Layout]) {
if toggleBetween.isEmpty {
return nil
}
self.toggleBetween = toggleBetween
}

func run() async {
precondition(Thread.current.isMainThread)
// todo
guard let window = focusedWindow ?? Workspace.focused.mruWindows.mostRecent else { return }
let targetLayout = toggleBetween.firstIndex(of: window.verboseLayout)
.flatMap { toggleBetween.getOrNil(atIndex: $0 + 1) } ?? toggleBetween.first
if let parent = window.parent as? TilingContainer {
parent.layout = targetLayout?.simpleLayout ?? errorT("TODO")
parent.orientation = targetLayout?.orientation ?? errorT("TODO")
refresh()
} else {
precondition(window.parent is Workspace)
// todo
}
}
}

private extension LayoutCommand.Layout {
var simpleLayout: Layout? {
switch self {
case .h_accordion, .v_accordion:
return .Accordion
case .h_list, .v_list:
return .List
case .floating, .tiling:
return nil
}
}

var orientation: Orientation? {
switch self {
case .h_accordion, .h_list:
return .H
case .v_accordion, .v_list:
return .V
case .floating, .tiling:
return nil
}
}
}

private extension MacWindow {
var verboseLayout: LayoutCommand.Layout {
(parent as? TilingContainer).flatMap {
switch $0.layout {
case .List:
return $0.orientation == .H ? .h_list : .v_list
case .Accordion:
return $0.orientation == .H ? .h_accordion : .v_accordion
}
} ?? .floating
}
}
5 changes: 5 additions & 0 deletions src/command/parseCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ private func parseSingleCommand(_ raw: String, _ backtrace: TomlBacktrace) -> Co
let direction = MoveThroughCommand.Direction(rawValue: parseSingleArg(args, firstWord, backtrace))
?? errorT("\(backtrace): Can't parse '\(firstWord)' direction")
return MoveThroughCommand(direction: direction)
} else if firstWord == "layout" {
let layouts = args.map {
LayoutCommand.Layout(rawValue: String($0)) ?? errorT("Can't parse layout arg '\($0)'")
}
return LayoutCommand(toggleBetween: layouts) ?? errorT("Can't create layout command")
} else if raw == "workspace_back_and_forth" {
return WorkspaceBackAndForth()
} else if raw == "reload_config" {
Expand Down
12 changes: 6 additions & 6 deletions src/tree/TreeNodeEx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ extension TreeNode {
self as? Workspace ?? parent.workspace
}

func allLeafWindowsRecursive(snappedTo: CardinalDirection) -> [MacWindow] {
func allLeafWindowsRecursive(snappedTo direction: CardinalDirection) -> [MacWindow] {
if let workspace = self as? Workspace {
return workspace.rootTilingContainer.allLeafWindowsRecursive(snappedTo: snappedTo)
return workspace.rootTilingContainer.allLeafWindowsRecursive(snappedTo: direction)
} else if let window = self as? MacWindow {
return [window]
} else if let container = self as? TilingContainer {
if snappedTo.orientation == container.orientation {
return (snappedTo.isPositive ? container.children.last : container.children.first)?
.allLeafWindowsRecursive(snappedTo: snappedTo) ?? []
if direction.orientation == container.orientation {
return (direction.isPositive ? container.children.last : container.children.first)?
.allLeafWindowsRecursive(snappedTo: direction) ?? []
} else {
return children.flatMap { $0.allLeafWindowsRecursive(snappedTo: snappedTo) }
return children.flatMap { $0.allLeafWindowsRecursive(snappedTo: direction) }
}
} else {
error("Not supported TreeNode type: \(Self.self)")
Expand Down

0 comments on commit 5180eb8

Please sign in to comment.