Module: Ace::Tmux::Atoms::LayoutStringBuilder
- Defined in:
- lib/ace/tmux/atoms/layout_string_builder.rb
Overview
Pure function that builds a tmux custom layout string from a LayoutNode tree.
Takes a tree of LayoutNode objects, window dimensions, and pane IDs, then produces a tmux layout string like:
"a]b4,200x50,0,0{80x50,0,0,0,119x50,81,0[119x25,81,0,1,119x24,81,26,2]}"
tmux layout string format:
- `{...}` = horizontal split (children side by side)
- `[...]` = vertical split (children stacked)
- Leaf: `WxH,xoff,yoff,pane_id`
- Container: `WxH,xoff,yoff{child1,child2,...}` or `WxH,xoff,yoff[child1,child2,...]`
Class Method Summary collapse
-
.allocate_sizes(children, total:) ⇒ Array<Integer>
Allocate cell sizes for children along the split axis.
- .brackets_for(direction) ⇒ Object private
-
.build(root, width:, height:, pane_ids:) ⇒ String
Build a complete tmux layout string with checksum.
- .child_dimensions(direction, parent_w, parent_h, size) ⇒ Object
- .child_offsets(direction, parent_x, parent_y, offset) ⇒ Object
-
.generate_node(node, x:, y:, width:, height:) ⇒ String
Recursively generate the layout string for a node.
-
.layout_checksum(str) ⇒ String
Compute tmux layout checksum (CRC16 variant: rotate-right-and-add).
-
.parse_size(size, total) ⇒ Integer?
Parse an explicit size value into cells.
- .split_dimension(direction, width, height) ⇒ Object
- .split_offset(direction, x, y) ⇒ Object
Class Method Details
.allocate_sizes(children, total:) ⇒ Array<Integer>
Allocate cell sizes for children along the split axis.
Handles explicit sizes (percentage or absolute) and distributes remaining space evenly among auto-sized children. Accounts for 1-cell separators between adjacent panes.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 79 def allocate_sizes(children, total:) separator_count = children.length - 1 available = total - separator_count sizes = children.map { |child| parse_size(child.size, available) } # Distribute remaining space among auto-sized children claimed = sizes.compact.sum auto_count = sizes.count(&:nil?) if auto_count > 0 remaining = available - claimed base = remaining / auto_count extra = remaining % auto_count auto_index = 0 sizes = sizes.map do |s| next s unless s.nil? # Give extra cells to the first auto children cell_size = base + ((auto_index < extra) ? 1 : 0) auto_index += 1 cell_size end end sizes end |
.brackets_for(direction) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
138 139 140 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 138 def brackets_for(direction) (direction == :horizontal) ? ["{", "}"] : ["[", "]"] end |
.build(root, width:, height:, pane_ids:) ⇒ String
Build a complete tmux layout string with checksum.
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 27 def build(root, width:, height:, pane_ids:) # Assign pane IDs to leaves in DFS order # Fall back to sequential index if pane_ids is shorter than leaves leaves = root.leaves leaves.each_with_index { |leaf, i| leaf.pane_id = pane_ids[i] || i } body = generate_node(root, x: 0, y: 0, width: width, height: height) checksum = layout_checksum(body) "#{checksum},#{body}" end |
.child_dimensions(direction, parent_w, parent_h, size) ⇒ Object
153 154 155 156 157 158 159 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 153 def child_dimensions(direction, parent_w, parent_h, size) if direction == :horizontal [size, parent_h] else [parent_w, size] end end |
.child_offsets(direction, parent_x, parent_y, offset) ⇒ Object
162 163 164 165 166 167 168 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 162 def child_offsets(direction, parent_x, parent_y, offset) if direction == :horizontal [offset, parent_y] else [parent_x, offset] end end |
.generate_node(node, x:, y:, width:, height:) ⇒ String
Recursively generate the layout string for a node.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 46 def generate_node(node, x:, y:, width:, height:) if node.leaf? "#{width}x#{height},#{x},#{y},#{node.pane_id}" else sizes = allocate_sizes(node.children, total: split_dimension(node.direction, width, height)) open_bracket, close_bracket = brackets_for(node.direction) child_strings = [] offset = split_offset(node.direction, x, y) node.children.each_with_index do |child, i| child_w, child_h = child_dimensions(node.direction, width, height, sizes[i]) child_x, child_y = child_offsets(node.direction, x, y, offset) child_strings << generate_node(child, x: child_x, y: child_y, width: child_w, height: child_h) # Advance offset past this child + 1-cell separator (except after last) offset += sizes[i] + 1 end "#{width}x#{height},#{x},#{y}#{open_bracket}#{child_strings.join(",")}#{close_bracket}" end end |
.layout_checksum(str) ⇒ String
Compute tmux layout checksum (CRC16 variant: rotate-right-and-add).
128 129 130 131 132 133 134 135 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 128 def layout_checksum(str) csum = 0 str.each_byte do |byte| csum = ((csum >> 1) | ((csum & 1) << 15)) + byte csum &= 0xffff end format("%04x", csum) end |
.parse_size(size, total) ⇒ Integer?
Parse an explicit size value into cells.
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 113 def parse_size(size, total) return nil if size.nil? size = size.to_s if size.end_with?("%") (total * size.to_f / 100).round else size.to_i end end |
.split_dimension(direction, width, height) ⇒ Object
143 144 145 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 143 def split_dimension(direction, width, height) (direction == :horizontal) ? width : height end |
.split_offset(direction, x, y) ⇒ Object
148 149 150 |
# File 'lib/ace/tmux/atoms/layout_string_builder.rb', line 148 def split_offset(direction, x, y) (direction == :horizontal) ? x : y end |