Skip to content

Commit f516db6

Browse files
committed
Move VimFolds around
1 parent 0acf2a9 commit f516db6

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed

Local/VimFolds.pm

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package Local::VimFolds;
2+
3+
use strict;
4+
use warnings;
5+
use autodie;
6+
use parent 'Exporter';
7+
8+
use Carp qw(croak);
9+
use IO::Pty;
10+
use File::Temp;
11+
12+
use Test::More;
13+
use Test::Deep;
14+
15+
my $FOLD_RE = qr{
16+
\s* [#] \s*
17+
(?:
18+
(?:[{][{][{])
19+
|
20+
(?:[}][}][}])
21+
)
22+
\s* $
23+
}xm;
24+
25+
sub new {
26+
my ( $class, %params ) = @_;
27+
28+
if(my $options = $params{'options'}) {
29+
$params{'script_before'} = join(' | ', map {
30+
"let $_=" . $options->{$_}
31+
} keys %$options);
32+
}
33+
34+
return bless { %params }, $class;
35+
}
36+
37+
sub _get_folds {
38+
my ( $self, $filename ) = @_;
39+
40+
my $script_before = $self->{'script_before'} || '';
41+
my $syntax_file = 'syntax/' . $self->{'language'} . '.vim';
42+
43+
my $script_file = File::Temp->new(SUFFIX => '.vim');
44+
my $dump_file = File::Temp->new;
45+
close $dump_file;
46+
my $dump_file_name = $dump_file->filename;
47+
48+
print { $script_file } <<"END_VIM";
49+
$script_before
50+
51+
source $syntax_file
52+
53+
function DumpFoldsAndQuit()
54+
let folds = []
55+
let num_lines = line('\$')
56+
let max_fold_level = -1
57+
58+
let line_num = 1
59+
60+
while line_num <= num_lines
61+
let line_num = line_num + 1
62+
63+
let fold_level = foldlevel(line_num)
64+
65+
if fold_level > max_fold_level
66+
let max_fold_level = fold_level
67+
endif
68+
endwhile
69+
70+
let fold_level = max_fold_level
71+
72+
while fold_level >= 0
73+
let &foldlevel = fold_level
74+
let line_num = 1
75+
76+
while line_num <= num_lines
77+
let fold_start = foldclosed(line_num)
78+
79+
if fold_start == -1
80+
let line_num = line_num + 1
81+
else
82+
let fold_end = foldclosedend(line_num)
83+
84+
call add(folds, join([ fold_start, fold_end, &foldlevel ], ','))
85+
86+
let line_num = fold_end + 1
87+
endif
88+
endwhile
89+
90+
let fold_level = fold_level - 1
91+
endwhile
92+
93+
call writefile(folds, '$dump_file_name')
94+
quit
95+
endfunction
96+
END_VIM
97+
98+
my $pty = IO::Pty->new;
99+
my $pid = fork;
100+
101+
croak "Unable to fork" unless defined $pid;
102+
103+
if($pid) {
104+
$pty->close_slave;
105+
$pty->set_raw;
106+
sleep 1; # wait for folds to be set up
107+
print { $pty } ":call DumpFoldsAndQuit()\n";
108+
while(<$pty>) {
109+
# just read until the child is done
110+
}
111+
close $pty;
112+
waitpid $pid, 0;
113+
} else {
114+
$pty->make_slave_controlling_terminal;
115+
my $slave = $pty->slave;
116+
$slave->clone_winsize_from(\*STDIN);
117+
$slave->set_raw;
118+
119+
open STDIN, '<&', $slave->fileno;
120+
open STDOUT, '>&', $slave->fileno;
121+
open STDERR, '>&', $slave->fileno;
122+
123+
close $slave;
124+
125+
exec 'vim', '-u', $script_file->filename, $filename;
126+
}
127+
128+
my @folds;
129+
130+
my $fh;
131+
132+
open $fh, '<', $dump_file_name;
133+
while(<$fh>) {
134+
chomp;
135+
136+
my ( $start, $end, $level ) = split /,/;
137+
push @folds, {
138+
start => $start,
139+
end => $end,
140+
level => $level,
141+
};
142+
}
143+
close $fh;
144+
145+
return @folds;
146+
}
147+
148+
sub _find_expected_folds {
149+
my ( $self, $code ) = @_;
150+
151+
my @folds;
152+
my @fold_stack;
153+
154+
my $line_no = 1;
155+
foreach my $line (split /\n/, $code) {
156+
if($line =~ /\Q{{{\E/) {
157+
push @fold_stack, $line_no;
158+
} elsif($line =~ /\Q}}}\E/) {
159+
my $start = pop @fold_stack;
160+
push @folds, {
161+
start => $start,
162+
end => $line_no,
163+
};
164+
}
165+
$line_no++;
166+
}
167+
168+
return @folds;
169+
}
170+
171+
sub folds_match {
172+
my ( $self, $code, $name ) = @_;
173+
174+
my $tempfile = File::Temp->new;
175+
my $foldless_code = $code;
176+
$foldless_code =~ s/$FOLD_RE//g;
177+
print { $tempfile } $foldless_code;
178+
close $tempfile;
179+
180+
my @expected_folds = $self->_find_expected_folds($code);
181+
my @got_folds = $self->_get_folds($tempfile->filename);
182+
183+
foreach my $fold (@got_folds) {
184+
delete $fold->{'level'};
185+
}
186+
local $Test::Builder::Level = $Test::Builder::Level + 1;
187+
188+
unless(cmp_set(\@got_folds, \@expected_folds, $name)) {
189+
diag('Got: ' . join('', explain(\@got_folds)));
190+
diag('Expected: ' . join('', explain(\@expected_folds)));
191+
}
192+
}
193+
194+
1;

0 commit comments

Comments
 (0)