line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# Copyright (C) 2015-2019 Joelle Maslak |
3
|
|
|
|
|
|
|
# All Rights Reserved - See License |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Term::Tmux::Layout; |
7
|
|
|
|
|
|
|
$Term::Tmux::Layout::VERSION = '1.192431'; |
8
|
2
|
|
|
2
|
|
80162
|
use v5.8; |
|
2
|
|
|
|
|
6
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# ABSTRACT: Create tmux layout strings programmatically |
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
9
|
use strict; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
36
|
|
13
|
2
|
|
|
2
|
|
7
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
59
|
|
14
|
2
|
|
|
2
|
|
590
|
use autodie; |
|
2
|
|
|
|
|
13940
|
|
|
2
|
|
|
|
|
12
|
|
15
|
|
|
|
|
|
|
|
16
|
2
|
|
|
2
|
|
10843
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
159
|
|
17
|
2
|
|
|
2
|
|
1346
|
use Moose; |
|
2
|
|
|
|
|
885822
|
|
|
2
|
|
|
|
|
15
|
|
18
|
2
|
|
|
2
|
|
15169
|
use namespace::autoclean; |
|
2
|
|
|
|
|
15453
|
|
|
2
|
|
|
|
|
10
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub set_layout { |
23
|
0
|
0
|
|
0
|
1
|
0
|
if ( $#_ < 1 ) { confess 'invalid call' } |
|
0
|
|
|
|
|
0
|
|
24
|
0
|
|
|
|
|
0
|
my ( $self, @def ) = @_; |
25
|
|
|
|
|
|
|
|
26
|
0
|
|
|
|
|
0
|
my ( $x, $y ) = $self->get_window_size(); |
27
|
0
|
0
|
|
|
|
0
|
if ( !defined($y) ) { die "Cannot get the current tmux window size"; } |
|
0
|
|
|
|
|
0
|
|
28
|
|
|
|
|
|
|
|
29
|
0
|
|
|
|
|
0
|
$self->hsize($x); |
30
|
0
|
|
|
|
|
0
|
$self->vsize($y); |
31
|
|
|
|
|
|
|
|
32
|
0
|
|
|
|
|
0
|
my $layout = $self->layout(@def); |
33
|
0
|
|
|
|
|
0
|
system( 'tmux', 'select-layout', $layout ); |
34
|
0
|
0
|
|
|
|
0
|
if ($@) { |
35
|
0
|
|
|
|
|
0
|
die('Could not set layout'); |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
0
|
|
|
|
|
0
|
return $layout; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub layout { |
43
|
11
|
50
|
|
11
|
1
|
6016
|
if ( $#_ < 1 ) { confess 'invalid call' } |
|
0
|
|
|
|
|
0
|
|
44
|
11
|
|
|
|
|
26
|
my ( $self, @desc ) = @_; |
45
|
|
|
|
|
|
|
|
46
|
11
|
|
|
|
|
62
|
my @rows = split /[\n|]/, join( '|', @desc ); |
47
|
11
|
|
|
|
|
22
|
my $width = length( $rows[0] ); |
48
|
11
|
|
|
|
|
22
|
foreach (@rows) { |
49
|
17
|
50
|
|
|
|
38
|
if ( $width != length($_) ) { |
50
|
0
|
|
|
|
|
0
|
croak 'All rows must be the same length'; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
11
|
|
|
|
|
22
|
my $desc = join '|', @desc; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Where are my divisions? |
57
|
11
|
|
|
|
|
378
|
my $hdiv = $self->hsize / ( $width * 1.0 ); |
58
|
11
|
|
|
|
|
290
|
my $vdiv = $self->vsize / ( scalar(@rows) * 1.0 ); |
59
|
|
|
|
|
|
|
|
60
|
11
|
|
|
|
|
35
|
my @v_grid; |
61
|
11
|
|
|
|
|
29
|
for ( my $i = 0; $i < scalar(@rows); $i++ ) { |
62
|
17
|
|
|
|
|
56
|
$v_grid[$i] = int( $vdiv * $i + .5 ); |
63
|
|
|
|
|
|
|
} |
64
|
11
|
|
|
|
|
17
|
my @h_grid; |
65
|
11
|
|
|
|
|
27
|
for ( my $i = 0; $i < length( $rows[0] ); $i++ ) { |
66
|
29
|
|
|
|
|
60
|
$h_grid[$i] = int( $hdiv * $i + .5 ); |
67
|
|
|
|
|
|
|
} |
68
|
11
|
|
|
|
|
286
|
push @h_grid, $self->hsize + 1; |
69
|
11
|
|
|
|
|
271
|
push @v_grid, $self->vsize + 1; |
70
|
|
|
|
|
|
|
|
71
|
11
|
|
|
|
|
68
|
my %gridstruct = ( |
72
|
|
|
|
|
|
|
hgrid => \@h_grid, # H Start positions for each pane |
73
|
|
|
|
|
|
|
vgrid => \@v_grid, # V Start positions for each pane |
74
|
|
|
|
|
|
|
hparent => 0, # absolute start x position of enclosing window |
75
|
|
|
|
|
|
|
vparent => 0, # absolute start y position of enclosing window |
76
|
|
|
|
|
|
|
hoffset => 0, # We are drawing division at child relative grid location x |
77
|
|
|
|
|
|
|
voffset => 0, # We are drawing division at child relative location x |
78
|
|
|
|
|
|
|
hsize => $#h_grid, # Child grid size X |
79
|
|
|
|
|
|
|
vsize => $#v_grid, # Child grid size Y |
80
|
|
|
|
|
|
|
layout => $desc |
81
|
|
|
|
|
|
|
); |
82
|
11
|
|
|
|
|
27
|
my $result = $self->_divide( \%gridstruct ); |
83
|
11
|
|
|
|
|
29
|
return $self->checksum($result) . ",$result"; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub _divide { |
87
|
27
|
50
|
|
27
|
|
60
|
if ( $#_ != 1 ) { confess 'invalid call' } |
|
0
|
|
|
|
|
0
|
|
88
|
27
|
|
|
|
|
51
|
my ( $self, $gridstruct ) = @_; |
89
|
|
|
|
|
|
|
|
90
|
27
|
|
|
|
|
56
|
my (@map) = $self->_make_map( $gridstruct->{layout} ); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Check 1: Are we done (I.E. only one pane left)? |
93
|
27
|
|
|
|
|
35
|
my %panes; |
94
|
27
|
|
|
|
|
52
|
foreach my $r (@map) { |
95
|
41
|
|
|
|
|
54
|
foreach my $c (@$r) { |
96
|
84
|
|
|
|
|
141
|
$panes{$c} = 1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Absolute Location, in grid units, of H and V of parent |
101
|
27
|
|
|
|
|
44
|
my $h_grid_parent_b = $gridstruct->{hparent}; |
102
|
27
|
|
|
|
|
35
|
my $v_grid_parent_b = $gridstruct->{vparent}; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# Absolute Location, in colrow of start of parent division |
105
|
27
|
|
|
|
|
41
|
my $h_char_parent_b = $gridstruct->{hgrid}->[$h_grid_parent_b]; |
106
|
27
|
|
|
|
|
39
|
my $v_char_parent_b = $gridstruct->{vgrid}->[$v_grid_parent_b]; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Absolute Grid location of H and V start of this division |
109
|
27
|
|
|
|
|
43
|
my $h_grid_abs_b = $gridstruct->{hparent} + $gridstruct->{hoffset}; |
110
|
27
|
|
|
|
|
39
|
my $v_grid_abs_b = $gridstruct->{vparent} + $gridstruct->{voffset}; |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# Absolute Locations, in grid units, of end+1 of this division |
113
|
27
|
|
|
|
|
42
|
my $h_grid_abs_n = $h_grid_abs_b + $gridstruct->{hsize}; |
114
|
27
|
|
|
|
|
37
|
my $v_grid_abs_n = $v_grid_abs_b + $gridstruct->{vsize}; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Absolute Location, in col/row, of start of this division |
117
|
27
|
|
|
|
|
39
|
my $h_char_abs_b = $gridstruct->{hgrid}->[$h_grid_abs_b]; |
118
|
27
|
|
|
|
|
39
|
my $v_char_abs_b = $gridstruct->{vgrid}->[$v_grid_abs_b]; |
119
|
27
|
100
|
|
|
|
52
|
if ( $h_char_abs_b > 0 ) { $h_char_abs_b++; } # Adjust for pane border |
|
9
|
|
|
|
|
11
|
|
120
|
27
|
50
|
|
|
|
51
|
if ( $v_char_abs_b > 0 ) { $v_char_abs_b++; } # Adjust for pane border |
|
0
|
|
|
|
|
0
|
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Absolute Location, in col/row of end+1 of this division |
123
|
27
|
|
|
|
|
42
|
my $h_char_abs_n = $gridstruct->{hgrid}->[$h_grid_abs_n]; |
124
|
27
|
|
|
|
|
36
|
my $v_char_abs_n = $gridstruct->{vgrid}->[$v_grid_abs_n]; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Relative Position (to parent) of start of this division |
127
|
27
|
|
|
|
|
47
|
my $h_char_rel_b = $h_char_abs_b - $h_char_parent_b; |
128
|
27
|
|
|
|
|
40
|
my $v_char_rel_b = $v_char_abs_b - $v_char_parent_b; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# Relative Position (to parent) of next division |
131
|
27
|
|
|
|
|
35
|
my $h_char_rel_n = $h_char_abs_n - $h_char_parent_b; |
132
|
27
|
|
|
|
|
37
|
my $v_char_rel_n = $v_char_abs_n - $v_char_parent_b; |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# Division width/height in col/rows |
135
|
27
|
|
|
|
|
35
|
my $h_size = $h_char_rel_n - $h_char_rel_b; |
136
|
27
|
|
|
|
|
1220
|
my $v_size = $v_char_rel_n - $v_char_rel_b; |
137
|
27
|
100
|
|
|
|
58
|
if ( $h_char_abs_b == 0 ) { $h_size--; } |
|
18
|
|
|
|
|
37
|
|
138
|
27
|
50
|
|
|
|
46
|
if ( $v_char_abs_b == 0 ) { $v_size--; } |
|
27
|
|
|
|
|
35
|
|
139
|
|
|
|
|
|
|
|
140
|
27
|
|
|
|
|
68
|
my $result = "${h_size}x${v_size},${h_char_abs_b},${v_char_abs_b}"; |
141
|
|
|
|
|
|
|
|
142
|
27
|
100
|
|
|
|
61
|
if ( scalar( keys %panes ) == 1 ) { |
143
|
|
|
|
|
|
|
# We throw in a bogus pane value because it is ignroed anyhow |
144
|
19
|
|
|
|
|
84
|
return "$result,100"; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Check 2: Can we do a vertical split? |
148
|
|
|
|
|
|
|
NEXTV: |
149
|
8
|
|
|
|
|
16
|
for ( my $i = 1; $i < scalar( @{ $map[0] } ); $i++ ) { |
|
12
|
|
|
|
|
27
|
|
150
|
12
|
|
|
|
|
26
|
for ( my $j = 0; $j < scalar(@map); $j++ ) { |
151
|
16
|
100
|
|
|
|
76
|
if ( $map[$j]->[ $i - 1 ] eq $map[$j]->[$i] ) { |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Can't split here |
154
|
4
|
|
|
|
|
10
|
next NEXTV; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# We can split here! |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# TODO: We should check that we aren't allowing things |
161
|
|
|
|
|
|
|
# that are 0xY or Xx0 |
162
|
8
|
|
|
|
|
24
|
my (@vfield) = $self->_vsplit_field( $gridstruct->{layout}, $i ); |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my %left = ( |
165
|
|
|
|
|
|
|
hgrid => $gridstruct->{hgrid}, |
166
|
|
|
|
|
|
|
vgrid => $gridstruct->{vgrid}, |
167
|
|
|
|
|
|
|
hparent => $h_grid_abs_b, |
168
|
|
|
|
|
|
|
vparent => $v_grid_abs_b, |
169
|
|
|
|
|
|
|
hoffset => 0, |
170
|
|
|
|
|
|
|
voffset => 0, |
171
|
|
|
|
|
|
|
hsize => $i, |
172
|
|
|
|
|
|
|
vsize => $gridstruct->{vsize}, |
173
|
8
|
|
|
|
|
38
|
layout => $vfield[0] |
174
|
|
|
|
|
|
|
); |
175
|
|
|
|
|
|
|
my %right = ( |
176
|
|
|
|
|
|
|
hgrid => $gridstruct->{hgrid}, |
177
|
|
|
|
|
|
|
vgrid => $gridstruct->{vgrid}, |
178
|
|
|
|
|
|
|
hparent => $h_grid_abs_b, |
179
|
|
|
|
|
|
|
vparent => $v_grid_abs_b, |
180
|
|
|
|
|
|
|
hoffset => $i, |
181
|
|
|
|
|
|
|
voffset => 0, |
182
|
|
|
|
|
|
|
hsize => $gridstruct->{hsize} - $i, |
183
|
|
|
|
|
|
|
vsize => $gridstruct->{vsize}, |
184
|
8
|
|
|
|
|
36
|
layout => $vfield[1] |
185
|
|
|
|
|
|
|
); |
186
|
|
|
|
|
|
|
|
187
|
8
|
|
|
|
|
38
|
$result .= '{' . $self->_divide( \%left ) . ',' . $self->_divide( \%right ) . '}'; |
188
|
|
|
|
|
|
|
|
189
|
8
|
|
|
|
|
43
|
return $result; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Check 3: Can we do a horizontal split? |
193
|
|
|
|
|
|
|
NEXTH: |
194
|
0
|
|
|
|
|
0
|
for ( my $j = 1; $j < scalar(@map); $j++ ) { |
195
|
0
|
|
|
|
|
0
|
for ( my $i = 0; $i < scalar( @{ $map[0] } ); $i++ ) { |
|
0
|
|
|
|
|
0
|
|
196
|
0
|
0
|
|
|
|
0
|
if ( $map[ $j - 1 ]->[$i] eq $map[$j]->[$i] ) { |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# Can't split here |
199
|
0
|
|
|
|
|
0
|
next NEXTH; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
0
|
my (@hfield) = $self->_hsplit_field( $gridstruct->{layout}, $j ); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
my %left = ( |
206
|
|
|
|
|
|
|
hgrid => $gridstruct->{hgrid}, |
207
|
|
|
|
|
|
|
vgrid => $gridstruct->{vgrid}, |
208
|
|
|
|
|
|
|
hparent => $h_grid_abs_b, |
209
|
|
|
|
|
|
|
vparent => $v_grid_abs_b, |
210
|
|
|
|
|
|
|
hoffset => 0, |
211
|
|
|
|
|
|
|
voffset => 0, |
212
|
|
|
|
|
|
|
hsize => $gridstruct->{hsize}, |
213
|
0
|
|
|
|
|
0
|
vsize => $j, |
214
|
|
|
|
|
|
|
layout => $hfield[0] |
215
|
|
|
|
|
|
|
); |
216
|
|
|
|
|
|
|
my %right = ( |
217
|
|
|
|
|
|
|
hgrid => $gridstruct->{hgrid}, |
218
|
|
|
|
|
|
|
vgrid => $gridstruct->{vgrid}, |
219
|
|
|
|
|
|
|
hparent => $h_grid_abs_b, |
220
|
|
|
|
|
|
|
vparent => $v_grid_abs_b, |
221
|
|
|
|
|
|
|
hoffset => 0, |
222
|
|
|
|
|
|
|
voffset => $j, |
223
|
|
|
|
|
|
|
hsize => $gridstruct->{hsize}, |
224
|
0
|
|
|
|
|
0
|
vsize => $gridstruct->{vsize} - $j, |
225
|
|
|
|
|
|
|
layout => $hfield[1] |
226
|
|
|
|
|
|
|
); |
227
|
|
|
|
|
|
|
# We can split here! |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# TODO: We should check that we aren't allowing things |
230
|
|
|
|
|
|
|
# that are 0xY or Xx0 |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
0
|
$result .= '[' . $self->_divide( \%left ) . ',' . $self->_divide( \%right ) . ']'; |
233
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
0
|
return $result; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
0
|
die("Can't split"); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub _hsplit_field { |
241
|
0
|
0
|
|
0
|
|
0
|
if ( $#_ != 2 ) { confess 'invalid call'; } |
|
0
|
|
|
|
|
0
|
|
242
|
0
|
|
|
|
|
0
|
my ( $self, $field, $spos ) = @_; |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
0
|
my (@map) = $self->_make_map($field); |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
0
|
my (@split) = ( [], [] ); |
247
|
0
|
|
|
|
|
0
|
for ( my $i = 0; $i < scalar( @{ $map[0] } ); $i++ ) { |
|
0
|
|
|
|
|
0
|
|
248
|
0
|
|
|
|
|
0
|
for ( my $j = 0; $j < scalar(@map); $j++ ) { |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Create the row |
251
|
0
|
0
|
|
|
|
0
|
if ( $i == 0 ) { |
252
|
0
|
|
|
|
|
0
|
$split[0]->[$j] = []; |
253
|
0
|
|
|
|
|
0
|
$split[1]->[$j] = []; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
0
|
0
|
|
|
|
0
|
if ( $j < $spos ) { |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# First map |
259
|
0
|
|
|
|
|
0
|
$split[0]->[$j]->[$i] = $map[$j]->[$i]; |
260
|
|
|
|
|
|
|
} else { |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Second map |
263
|
0
|
|
|
|
|
0
|
$split[1]->[ $j - $spos ]->[$i] = $map[$j]->[$i]; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
0
|
my $field1 = join "\n", map { join '', @$_ } @{ $split[0] }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
269
|
0
|
|
|
|
|
0
|
my $field2 = join "\n", map { join '', @$_ } @{ $split[1] }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
270
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
0
|
return ( $field1, $field2 ); |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub _vsplit_field { |
275
|
8
|
50
|
|
8
|
|
18
|
if ( $#_ != 2 ) { confess 'invalid call'; } |
|
0
|
|
|
|
|
0
|
|
276
|
8
|
|
|
|
|
19
|
my ( $self, $field, $spos ) = @_; |
277
|
|
|
|
|
|
|
|
278
|
8
|
|
|
|
|
17
|
my (@map) = $self->_make_map($field); |
279
|
|
|
|
|
|
|
|
280
|
8
|
|
|
|
|
17
|
my (@split) = ( [], [] ); |
281
|
8
|
|
|
|
|
12
|
for ( my $i = 0; $i < scalar( @{ $map[0] } ); $i++ ) { |
|
34
|
|
|
|
|
64
|
|
282
|
26
|
|
|
|
|
49
|
for ( my $j = 0; $j < scalar(@map); $j++ ) { |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# Create the row |
285
|
39
|
100
|
|
|
|
63
|
if ( $i == 0 ) { |
286
|
12
|
|
|
|
|
20
|
$split[0]->[$j] = []; |
287
|
12
|
|
|
|
|
24
|
$split[1]->[$j] = []; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
39
|
100
|
|
|
|
64
|
if ( $i < $spos ) { |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# First map |
293
|
18
|
|
|
|
|
48
|
$split[0]->[$j]->[$i] = $map[$j]->[$i]; |
294
|
|
|
|
|
|
|
} else { |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# Second map |
297
|
21
|
|
|
|
|
51
|
$split[1]->[$j]->[ $i - $spos ] = $map[$j]->[$i]; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
8
|
|
|
|
|
15
|
my $field1 = join "\n", map { join '', @$_ } @{ $split[0] }; |
|
12
|
|
|
|
|
33
|
|
|
8
|
|
|
|
|
17
|
|
303
|
8
|
|
|
|
|
29
|
my $field2 = join "\n", map { join '', @$_ } @{ $split[1] }; |
|
12
|
|
|
|
|
27
|
|
|
8
|
|
|
|
|
11
|
|
304
|
|
|
|
|
|
|
|
305
|
8
|
|
|
|
|
31
|
return ( $field1, $field2 ); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub _make_map { |
309
|
35
|
50
|
|
35
|
|
63
|
if ( $#_ != 1 ) { confess 'invalid call' } |
|
0
|
|
|
|
|
0
|
|
310
|
35
|
|
|
|
|
64
|
my ( $self, $field ) = @_; |
311
|
|
|
|
|
|
|
|
312
|
35
|
50
|
|
|
|
78
|
if ( !defined($field) ) { confess 'Empty field!' } |
|
0
|
|
|
|
|
0
|
|
313
|
|
|
|
|
|
|
|
314
|
35
|
|
|
|
|
46
|
my @map; |
315
|
35
|
|
|
|
|
44
|
my $rpos = 0; |
316
|
35
|
|
|
|
|
108
|
foreach my $row ( split /[\n|]/, $field ) { |
317
|
53
|
|
|
|
|
69
|
my $cpos = 0; |
318
|
53
|
|
|
|
|
82
|
$map[$rpos] = []; |
319
|
53
|
|
|
|
|
105
|
foreach my $col ( split //, $row ) { |
320
|
123
|
|
|
|
|
196
|
$map[$rpos]->[$cpos] = $col; |
321
|
123
|
|
|
|
|
491
|
$cpos++; |
322
|
|
|
|
|
|
|
} |
323
|
53
|
|
|
|
|
91
|
$rpos++; |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
35
|
|
|
|
|
78
|
return @map; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub checksum { |
331
|
14
|
50
|
|
14
|
1
|
1567
|
if ( $#_ != 1 ) { confess 'invalid call'; } |
|
0
|
|
|
|
|
0
|
|
332
|
14
|
|
|
|
|
29
|
my ( $self, $str ) = @_; |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# We silently discard a newline if it appears. |
335
|
14
|
|
|
|
|
25
|
chomp($str); |
336
|
|
|
|
|
|
|
|
337
|
14
|
|
|
|
|
21
|
my $csum = 0; |
338
|
14
|
|
|
|
|
105
|
foreach my $c ( split //, $str ) { |
339
|
613
|
|
|
|
|
830
|
$csum = ( $csum >> 1 ) + ( ( $csum & 1 ) << 15 ) % 65536; |
340
|
613
|
|
|
|
|
751
|
$csum += ord($c); |
341
|
613
|
|
|
|
|
811
|
$csum %= 65536; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
14
|
|
|
|
|
130
|
return sprintf( "%04x", $csum ); |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub get_window_size { |
349
|
0
|
0
|
|
0
|
1
|
|
if ( scalar(@_) != 1 ) { confess 'invalid call' } |
|
0
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
|
351
|
0
|
|
|
|
|
|
my (@windows) = `tmux list-windows`; |
352
|
0
|
|
|
|
|
|
@windows = grep { /\(active\)$/ } map { chomp; $_ } @windows; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
|
354
|
0
|
0
|
|
|
|
|
if ( scalar(@windows) ) { |
355
|
0
|
|
|
|
|
|
my ( $x, $y ) = $windows[0] =~ / \[([0-9]+)x([0-9]+)\] /; |
356
|
0
|
|
|
|
|
|
return ( $x, $y ); |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
0
|
|
|
|
|
|
return; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
has 'hsize' => ( |
364
|
|
|
|
|
|
|
is => 'rw', |
365
|
|
|
|
|
|
|
isa => 'Int', |
366
|
|
|
|
|
|
|
default => 80 |
367
|
|
|
|
|
|
|
); |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
has 'vsize' => ( |
371
|
|
|
|
|
|
|
is => 'rw', |
372
|
|
|
|
|
|
|
isa => 'Int', |
373
|
|
|
|
|
|
|
default => 24 |
374
|
|
|
|
|
|
|
); |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
1; |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
__END__ |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=pod |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=encoding UTF-8 |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head1 NAME |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Term::Tmux::Layout - Create tmux layout strings programmatically |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head1 VERSION |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
version 1.192431 |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=head1 SYNOPSIS |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
my $layout = Term::Tmux::Layout->new(); |
398
|
|
|
|
|
|
|
my $checksum = $layout->set_layout('abc|def'); |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head1 DESCRIPTION |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
Set tmux pane layouts using via a simpler interface. See also L<tmuxlayout> |
403
|
|
|
|
|
|
|
which wraps this module in a command-line script. |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=head2 hsize |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
Defines the width of the terminal window (the entire canvas), |
410
|
|
|
|
|
|
|
with a default of 80. |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head2 vsize |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
Defines the height of the terminal window tmux canvas (does not |
415
|
|
|
|
|
|
|
include the status line and command line at the bottom, so this |
416
|
|
|
|
|
|
|
should be one line smaller than the actual terminal emulator |
417
|
|
|
|
|
|
|
window size). This defaults to 24. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head1 METHODS |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=head2 set_layout( $definition ) |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
This option sets the layout to the string definition provided. The string |
424
|
|
|
|
|
|
|
provided must follow the requirements of C<layout()> described elsewhere |
425
|
|
|
|
|
|
|
in this document. |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
This command will determine the current tmux window size (using |
428
|
|
|
|
|
|
|
C<get_window_size()>) and then calls C<layout()> to get the layout string |
429
|
|
|
|
|
|
|
in proper tmux format. Finally, it executes tmux to select that layout |
430
|
|
|
|
|
|
|
as the active layout. |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
You can only run this method from a tmux window. C<tmuxlayout> is a thin |
433
|
|
|
|
|
|
|
wrapper around this function. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head2 layout ( $layout ) |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
This method takes a "layout" in a text format, and outputs |
438
|
|
|
|
|
|
|
the proper output. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
The layout format consists of a text field of numbers or other |
441
|
|
|
|
|
|
|
characters, separated by new lines. Each character reflects a |
442
|
|
|
|
|
|
|
single pane on the screen, defining its' size in rows and |
443
|
|
|
|
|
|
|
columns. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Some sample layouts: |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
11123 |
448
|
|
|
|
|
|
|
11124 |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
This would create a layout with 4 panes. The panes would be |
451
|
|
|
|
|
|
|
arranged such that pane 1 takes up the entire vertical canvas, |
452
|
|
|
|
|
|
|
but only 3/5ths of the horizontal canvas. Pane 2 also takes up |
453
|
|
|
|
|
|
|
the entire vertical canvas, but only 1/5 of the horizontal |
454
|
|
|
|
|
|
|
canvas. Pane 3 and 4 are stacked, taking 1/5 of the horizontal |
455
|
|
|
|
|
|
|
canvas, evenly splitting the vertical canvas. |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Note that some layouts cannot be displayed by tmux. For example, |
458
|
|
|
|
|
|
|
the following would be invalid: |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
1122 |
461
|
|
|
|
|
|
|
1134 |
462
|
|
|
|
|
|
|
5556 |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Tmux divides the entire screen up either horizontally or vertically. |
465
|
|
|
|
|
|
|
However, there is no single horizontal or vertical split that would |
466
|
|
|
|
|
|
|
allow this screen to be divided. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
This layout can be passed a single scalar, where the rows are |
469
|
|
|
|
|
|
|
seperated by pipe characters C<|> or new lines. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
If this function is passed an array in the place of the definition, |
472
|
|
|
|
|
|
|
each element starts its own row. Each element can also contain pipe |
473
|
|
|
|
|
|
|
or newlines, and these are also interpreted as row deliminators. |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
Thus, the following are all valid calls to layout: |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
$obj->layout('abc|def|ghi'); |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
$obj->layout("abc\ndef\nghi"); |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
$obj->layout('abc', 'def', 'ghi'); |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
$obj->layout('abc|def', 'ghi'); |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=head2 checksum( $str ) |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
This method performs the tmux checksum, as described in the tmux |
488
|
|
|
|
|
|
|
source code in C<layout_checksum()>. The input value is the string |
489
|
|
|
|
|
|
|
without the checksum on the front. The output is the checksum |
490
|
|
|
|
|
|
|
value as a string (four hex characters). |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head2 get_window_size( ) |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
This method fetches the window size for the currently active tmux |
495
|
|
|
|
|
|
|
window. If tmux is not running, it instead returns C<undef>. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head2 new |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
my $layout = Term::Tmux::Layout( hsize => 80, vsize => 23 ); |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
Create a new layout class. Optionally takes named parameters |
502
|
|
|
|
|
|
|
for the C<hsize> and C<vsize>. |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=head1 TODO |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=over 4 |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=item * Break out command execution |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
There probably should be a Term::Tmux::Command module to execute tmux |
511
|
|
|
|
|
|
|
commands, rather than having the window size commands executed directly |
512
|
|
|
|
|
|
|
by this module. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=back |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=head1 REPOSITORY |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
L<https://github.com/jmaslak/Term-Tmux-Layout> |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=head1 SEE ALSO |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
See L<tmuxlayout> for a command line utility that wraps this module. |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=head1 BUGS |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
Check the issue tracker at: |
527
|
|
|
|
|
|
|
L<https://github.com/jmaslak/Term-Tmux-Layout/issues> |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head1 AUTHOR |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
Joelle Maslak <jmaslak@antelope.net> |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
This software is copyright (c) 2015-2018 by Joelle Maslak. |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
538
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=cut |