line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::VTide; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Created on: 2016-01-28 09:58:07 |
4
|
|
|
|
|
|
|
# Create by: Ivan Wills |
5
|
|
|
|
|
|
|
# $Id$ |
6
|
|
|
|
|
|
|
# $Revision$, $HeadURL$, $Date$ |
7
|
|
|
|
|
|
|
# $Revision$, $Source$, $Date$ |
8
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
359837
|
use Moo; |
|
6
|
|
|
|
|
57669
|
|
|
6
|
|
|
|
|
34
|
|
10
|
6
|
|
|
6
|
|
10140
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
192
|
|
11
|
6
|
|
|
6
|
|
2301
|
use version; |
|
6
|
|
|
|
|
10028
|
|
|
6
|
|
|
|
|
32
|
|
12
|
6
|
|
|
6
|
|
474
|
use Carp; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
349
|
|
13
|
6
|
|
|
6
|
|
2656
|
use English qw/ -no_match_vars /; |
|
6
|
|
|
|
|
18549
|
|
|
6
|
|
|
|
|
34
|
|
14
|
6
|
|
|
6
|
|
4971
|
use Getopt::Alt; |
|
6
|
|
|
|
|
3768710
|
|
|
6
|
|
|
|
|
45
|
|
15
|
6
|
|
|
6
|
|
28631
|
use App::VTide::Config; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
209
|
|
16
|
6
|
|
|
6
|
|
2749
|
use App::VTide::Hooks; |
|
6
|
|
|
|
|
38
|
|
|
6
|
|
|
|
|
273
|
|
17
|
6
|
|
|
6
|
|
43
|
use Path::Tiny; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
285
|
|
18
|
6
|
|
|
6
|
|
35
|
use YAML::Syck qw/ LoadFile DumpFile /; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
7672
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $VERSION = version->new('1.0.4'); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has config => ( |
23
|
|
|
|
|
|
|
is => 'rw', |
24
|
|
|
|
|
|
|
lazy => 1, |
25
|
|
|
|
|
|
|
default => sub { return App::VTide::Config->new() }, |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
has hooks => ( |
28
|
|
|
|
|
|
|
is => 'rw', |
29
|
|
|
|
|
|
|
lazy => 1, |
30
|
|
|
|
|
|
|
default => sub { return App::VTide::Hooks->new( vtide => $_[0] ) }, |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
has sub_commands => ( |
33
|
|
|
|
|
|
|
is => 'rw', |
34
|
|
|
|
|
|
|
lazy => 1, |
35
|
|
|
|
|
|
|
builder => '_sub_commands', |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub run { |
39
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
40
|
0
|
|
|
|
|
0
|
$self->config->history(@ARGV); |
41
|
0
|
|
|
|
|
0
|
my @sub_commands = keys %{ $self->sub_commands }; |
|
0
|
|
|
|
|
0
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
my ( $options, $cmd, $opt ) = get_options( |
44
|
|
|
|
|
|
|
{ |
45
|
|
|
|
|
|
|
name => 'vtide-cmd', |
46
|
|
|
|
|
|
|
conf_prefix => '.', |
47
|
|
|
|
|
|
|
helper => 1, |
48
|
|
|
|
|
|
|
default => { test => 0, }, |
49
|
|
|
|
|
|
|
auto_complete => sub { |
50
|
0
|
|
|
0
|
|
0
|
my ( $option, $auto, $errors ) = @_; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
my $sub_command = |
53
|
|
|
|
|
|
|
$option->cmd |
54
|
0
|
|
0
|
|
|
0
|
|| $ARGV[ $option->opt->{auto_complete} - 1 ] |
55
|
|
|
|
|
|
|
|| ''; |
56
|
0
|
0
|
0
|
|
|
0
|
if ( $sub_command eq '--' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
57
|
0
|
|
|
|
|
0
|
print join ' ', sort @sub_commands; |
58
|
0
|
|
|
|
|
0
|
return; |
59
|
|
|
|
|
|
|
} |
60
|
0
|
|
|
|
|
0
|
elsif ( $sub_command && grep { /^$sub_command./ } |
61
|
|
|
|
|
|
|
@sub_commands ) |
62
|
|
|
|
|
|
|
{ |
63
|
0
|
|
|
|
|
0
|
print join ' ', sort grep { /^$sub_command/ } @sub_commands; |
|
0
|
|
|
|
|
0
|
|
64
|
0
|
|
|
|
|
0
|
return; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
elsif ( !$self->sub_commands->{$sub_command} ) { |
67
|
0
|
|
|
|
|
0
|
unshift @{ $option->files }, $sub_command; |
|
0
|
|
|
|
|
0
|
|
68
|
0
|
0
|
|
|
|
0
|
$sub_command = $ENV{VTIDE_DIR} ? 'edit' : 'start'; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
eval { |
71
|
0
|
|
|
|
|
0
|
$self->load_subcommand( $sub_command, $option ) |
72
|
|
|
|
|
|
|
->auto_complete($auto); |
73
|
0
|
|
|
|
|
0
|
1; |
74
|
0
|
0
|
|
|
|
0
|
} or do { |
75
|
|
|
|
|
|
|
print join ' ', |
76
|
0
|
|
|
|
|
0
|
grep { /$sub_command/xms } sort @sub_commands; |
|
0
|
|
|
|
|
0
|
|
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
}, |
79
|
|
|
|
|
|
|
auto_complete_shortener => sub { |
80
|
0
|
|
|
0
|
|
0
|
my ( $getopt, @args ) = @_; |
81
|
0
|
|
0
|
|
|
0
|
my $sub_command = shift @args || ''; |
82
|
|
|
|
|
|
|
|
83
|
0
|
0
|
|
|
|
0
|
if ( grep { /^$sub_command./ } @sub_commands ) { |
|
0
|
0
|
|
|
|
0
|
|
84
|
0
|
0
|
|
|
|
0
|
if ( grep { $_ eq $sub_command } @sub_commands ) { |
|
0
|
|
|
|
|
0
|
|
85
|
0
|
|
|
|
|
0
|
$getopt->cmd($sub_command); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
else { |
88
|
0
|
|
|
|
|
0
|
unshift @args, $sub_command; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
elsif ( !$self->sub_commands->{$sub_command} ) { |
92
|
0
|
0
|
|
|
|
0
|
$getopt->cmd( $ENV{VTIDE_DIR} ? 'edit' : 'start' ); |
93
|
0
|
|
|
|
|
0
|
unshift @args, $sub_command; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
else { |
96
|
0
|
0
|
|
|
|
0
|
$getopt->cmd($sub_command) if !$getopt->cmd; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
0
|
return @args; |
100
|
|
|
|
|
|
|
}, |
101
|
|
|
|
|
|
|
sub_command => $self->sub_commands, |
102
|
|
|
|
|
|
|
help_package => __PACKAGE__, |
103
|
|
|
|
|
|
|
help_packages => { |
104
|
0
|
|
|
|
|
0
|
map { $_ => __PACKAGE__ . '::Command::' . ucfirst $_ } |
|
0
|
|
|
|
|
0
|
|
105
|
|
|
|
|
|
|
@sub_commands, |
106
|
|
|
|
|
|
|
}, |
107
|
|
|
|
|
|
|
}, |
108
|
|
|
|
|
|
|
[ |
109
|
|
|
|
|
|
|
'add|add-to-session|a', |
110
|
|
|
|
|
|
|
'update|u!', |
111
|
|
|
|
|
|
|
'name|n=s', |
112
|
|
|
|
|
|
|
'test|T!', |
113
|
|
|
|
|
|
|
'verbose|v+', |
114
|
|
|
|
|
|
|
], |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
0
|
if ( !$self->sub_commands->{ $opt->cmd } ) { |
118
|
0
|
|
|
|
|
0
|
unshift @ARGV, $opt->cmd; |
119
|
0
|
0
|
|
|
|
0
|
$opt->cmd( $ENV{VTIDE_DIR} ? 'edit' : 'start' ); |
120
|
0
|
|
|
|
|
0
|
$opt->files( \@ARGV ); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
0
|
my $subcommand = eval { $self->load_subcommand( $opt->cmd, $opt ) }; |
|
0
|
|
|
|
|
0
|
|
124
|
0
|
0
|
|
|
|
0
|
if ( !$subcommand ) { |
125
|
|
|
|
|
|
|
$subcommand = |
126
|
0
|
0
|
|
|
|
0
|
$self->load_subcommand( $ENV{VTIDE_DIR} ? 'edit' : 'start', $opt ); |
127
|
0
|
|
|
|
|
0
|
my ( undef, $dir ) = $subcommand->session_dir( $opt->cmd ); |
128
|
0
|
0
|
|
|
|
0
|
if ( !$dir ) { |
129
|
0
|
|
|
|
|
0
|
my $error = $@; |
130
|
0
|
0
|
|
|
|
0
|
warn $@ if $opt->opt->verbose; |
131
|
0
|
|
|
|
|
0
|
warn "Unknown command '$cmd'!\n", |
132
|
|
|
|
|
|
|
"Valid commands - ", ( join ', ', sort @sub_commands ), |
133
|
|
|
|
|
|
|
"\n"; |
134
|
0
|
|
|
|
|
0
|
require Pod::Usage; |
135
|
0
|
|
|
|
|
0
|
Pod::Usage::pod2usage( |
136
|
|
|
|
|
|
|
-verbose => 1, |
137
|
|
|
|
|
|
|
-input => __FILE__, |
138
|
|
|
|
|
|
|
); |
139
|
|
|
|
|
|
|
} |
140
|
0
|
|
|
|
|
0
|
unshift @{ $opt->files }, $opt->cmd; |
|
0
|
|
|
|
|
0
|
|
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
$subcommand->options->default( |
144
|
0
|
|
|
|
|
0
|
{ %{$options}, %{ $subcommand->options->default } } ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
145
|
|
|
|
|
|
|
eval { |
146
|
0
|
|
|
|
|
0
|
$subcommand->run; |
147
|
0
|
|
|
|
|
0
|
1; |
148
|
0
|
0
|
|
|
|
0
|
} or do { |
149
|
0
|
|
|
|
|
0
|
warn "Error running " . $opt->cmd . "!\n"; |
150
|
0
|
|
|
|
|
0
|
warn $@; |
151
|
0
|
|
|
|
|
0
|
sleep 5; |
152
|
|
|
|
|
|
|
}; |
153
|
0
|
|
|
|
|
0
|
return; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub load_subcommand { |
157
|
1
|
|
|
1
|
1
|
142309
|
my ( $self, $cmd, $opt ) = @_; |
158
|
|
|
|
|
|
|
|
159
|
1
|
|
|
|
|
7
|
my $file = 'App/VTide/Command/' . ucfirst $cmd . '.pm'; |
160
|
1
|
|
|
|
|
4
|
my $module = 'App::VTide::Command::' . ucfirst $cmd; |
161
|
|
|
|
|
|
|
|
162
|
1
|
|
|
|
|
569
|
require $file; |
163
|
|
|
|
|
|
|
|
164
|
1
|
|
|
|
|
38
|
return $module->new( |
165
|
|
|
|
|
|
|
defaults => $opt->opt, |
166
|
|
|
|
|
|
|
options => $opt, |
167
|
|
|
|
|
|
|
vtide => $self, |
168
|
|
|
|
|
|
|
); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub _sub_commands { |
172
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
173
|
0
|
|
|
|
|
|
my $sub_file = path $ENV{HOME}, '.vtide', 'sub-commands.yml'; |
174
|
|
|
|
|
|
|
|
175
|
0
|
0
|
|
|
|
|
mkdir $sub_file->parent if !-d $sub_file->parent; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
#if ( -f $sub_file && path($0)->stat->mtime ne $sub_file->stat->mtime ) { |
178
|
|
|
|
|
|
|
# unlink $sub_file; |
179
|
|
|
|
|
|
|
#} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
#return LoadFile("$sub_file") if -f $sub_file; |
182
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
return $self->_generate_sub_command(); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub _generate_sub_command { |
187
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
188
|
0
|
|
|
|
|
|
my $sub_file = path $ENV{HOME}, '.vtide', 'sub-commands.yml'; |
189
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
require Module::Pluggable; |
191
|
0
|
|
|
|
|
|
Module::Pluggable->import( |
192
|
|
|
|
|
|
|
require => 1, |
193
|
|
|
|
|
|
|
search_path => ['App::VTide::Command'] |
194
|
|
|
|
|
|
|
); |
195
|
0
|
|
|
|
|
|
my @commands = __PACKAGE__->plugins; |
196
|
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
|
my $sub_commands = {}; |
198
|
0
|
|
|
|
|
|
for my $command ( reverse sort @commands ) { |
199
|
0
|
|
|
|
|
|
my ( $name, $conf ) = $command->details_sub; |
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
|
$sub_commands->{$name} = $conf; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
|
DumpFile( $sub_file, $sub_commands ); |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
return $sub_commands; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
1; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
__END__ |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 NAME |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
App::VTide - A vim/tmux based IDE for the terminal |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 VERSION |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
This documentation refers to App::VTide version 1.0.4 |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 SYNOPSIS |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Session level |
224
|
|
|
|
|
|
|
vtide init |
225
|
|
|
|
|
|
|
vtide [start] [project] |
226
|
|
|
|
|
|
|
With in a session |
227
|
|
|
|
|
|
|
vtide (edit|run|conf|grep|recent|split|refresh|save|sessions|help) [options] |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
COMMANDS: |
230
|
|
|
|
|
|
|
conf Show editor config settings |
231
|
|
|
|
|
|
|
edit Run vim for a group of files |
232
|
|
|
|
|
|
|
grep Run grep against configured globs |
233
|
|
|
|
|
|
|
help Show help for vtide sub commands |
234
|
|
|
|
|
|
|
init Initialise a new project |
235
|
|
|
|
|
|
|
recent List recently run vtide sessions |
236
|
|
|
|
|
|
|
refresh Refreshes the autocomplete cache |
237
|
|
|
|
|
|
|
run Run a projects terminal command |
238
|
|
|
|
|
|
|
save Make/Save changes to a projects config file |
239
|
|
|
|
|
|
|
sessions |
240
|
|
|
|
|
|
|
run of save a session |
241
|
|
|
|
|
|
|
split Simply split up a tmux widow (using the same syntax as the config) |
242
|
|
|
|
|
|
|
start Open a project in Tmux |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
Examples: |
245
|
|
|
|
|
|
|
# start a new project, name taken from the directory name |
246
|
|
|
|
|
|
|
vtide init |
247
|
|
|
|
|
|
|
# start a new project specifying the project name |
248
|
|
|
|
|
|
|
vtide init --name my-project |
249
|
|
|
|
|
|
|
# start the project in the current directory |
250
|
|
|
|
|
|
|
vtide start |
251
|
|
|
|
|
|
|
# start the "my-project" project previously initialised |
252
|
|
|
|
|
|
|
vtide start my-project |
253
|
|
|
|
|
|
|
# Shortcuts |
254
|
|
|
|
|
|
|
# When not in a tmux session starting a new session |
255
|
|
|
|
|
|
|
vtide my-project |
256
|
|
|
|
|
|
|
# When in a tmux session you can run edit with out specifying it |
257
|
|
|
|
|
|
|
vtide my-glob |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head1 DESCRIPTION |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
VTide provides a way to manage L<tmux> sessions. It allows for an easy way |
262
|
|
|
|
|
|
|
to configure a session window and run programs or open files for editing |
263
|
|
|
|
|
|
|
in them. The aim is to allow for easy project setup and management for |
264
|
|
|
|
|
|
|
projects managed on the command line. L<App::VTide> also includes helpers |
265
|
|
|
|
|
|
|
for loading files into editors (such as vim) in separate tmux terminals. |
266
|
|
|
|
|
|
|
This can help to open pre-defined groups of files. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=head2 Philosophy |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
One piece of work == one project == one terminal tab. In one terminal |
271
|
|
|
|
|
|
|
tmux is run with tmux windows for editing different files, running commands |
272
|
|
|
|
|
|
|
and version control work. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head2 C<run ()> |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
Run the vtide commands |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head2 C<load_subcommand ( $cmd, $opt )> |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Loads the sub-command module and creates a new instance of it to return |
283
|
|
|
|
|
|
|
to the caller. |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head1 DIAGNOSTICS |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=head1 CONFIGURATION AND ENVIRONMENT |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
A full description of the configuration files can be found in |
290
|
|
|
|
|
|
|
L<App::VTide::Configuration>. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head1 INCOMPATIBILITIES |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head1 BUGS AND LIMITATIONS |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
There are no known bugs in this module. |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Please report problems to Ivan Wills (ivan.wills@gmail.com). |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Patches are welcome. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head1 AUTHOR |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Ivan Wills - (ivan.wills@gmail.com) |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Copyright (c) 2016 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077). |
311
|
|
|
|
|
|
|
All rights reserved. |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it under |
314
|
|
|
|
|
|
|
the same terms as Perl itself. See L<perlartistic>. This program is |
315
|
|
|
|
|
|
|
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
316
|
|
|
|
|
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
317
|
|
|
|
|
|
|
PARTICULAR PURPOSE. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=cut |