File Coverage

blib/lib/Term/CallEditor.pm
Criterion Covered Total %
statement 58 80 72.5
branch 21 46 45.6
condition 5 11 45.4
subroutine 9 10 90.0
pod 1 1 100.0
total 94 148 63.5


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             #
3             # Solicits data from an external editor. Run perldoc(1) on this module
4             # for additional documentation.
5              
6             package Term::CallEditor;
7              
8 1     1   58534 use strict;
  1         2  
  1         24  
9 1     1   5 use warnings;
  1         10  
  1         32  
10              
11             require 5.008;
12              
13 1     1   4 use vars qw(@EXPORT @ISA $VERSION $errstr);
  1         2  
  1         84  
14             @EXPORT = qw(solicit);
15             @ISA = qw(Exporter);
16 1     1   5 use Exporter;
  1         2  
  1         41  
17              
18 1     1   661 use File::Temp qw(tempfile);
  1         18278  
  1         51  
19 1     1   8 use IO::Handle; # for way olden versions of Perl
  1         2  
  1         34  
20 1     1   460 use POSIX qw(getpgrp tcgetpgrp);
  1         5281  
  1         5  
21 1     1   1601 use Text::ParseWords qw(shellwords);
  1         1137  
  1         558  
22              
23             $VERSION = '1.00';
24              
25             sub solicit {
26 7     7 1 11533 my $message = shift;
27 7   50     23 my $params = shift || {};
28 7         17 $errstr = '';
29              
30 7 50 33     85 unless (exists $params->{skip_interative} and $params->{skip_interative}) {
31 0 0       0 return unless _is_interactive();
32             }
33              
34 7 50       21 File::Temp->safe_level($params->{safe_level}) if exists $params->{safe_level};
35 7         106 my ($tfh, $filename) = tempfile(UNLINK => 1);
36              
37 7 50 33     4723 unless ($tfh and $filename) {
38 0         0 $errstr = 'no temporary file';
39 0         0 return;
40             }
41              
42 7 100 66     39 if (exists $params->{binmode_layer}
    50          
43             and defined $params->{binmode_layer}) {
44 1         8 binmode($tfh, $params->{binmode_layer});
45             } elsif ($params->{BINMODE}) {
46 0         0 binmode($tfh);
47             }
48              
49 7         73 select((select($tfh), $|++)[0]);
50              
51 7 50       27 if (defined $message) {
52 7         33 my $ref = ref $message;
53 7 50       19 if (not $ref) {
    0          
    0          
    0          
    0          
54 7         269 print $tfh $message;
55             } elsif ($ref eq 'SCALAR') {
56 0         0 print $tfh $$message;
57             } elsif ($ref eq 'ARRAY') {
58 0         0 print $tfh "@$message";
59             } elsif ($ref eq 'GLOB') {
60 0         0 while (my $line = readline $message) {
61 0         0 print $tfh $line;
62             }
63             } elsif (UNIVERSAL::can($message, 'getlines')) {
64 0         0 print $tfh $message->getlines;
65             }
66             # Help the bits reach the disk
67 7         49 $tfh->flush();
68 7 50       72 $params->{NOSYNC} = 1 if $^O =~ m/Win32/;
69 7 50       22 if (!$params->{NOSYNC}) {
70 7         23453 $tfh->sync();
71             }
72             }
73              
74 7 50       72 my $ed = defined $params->{DEFAULT_EDITOR} ? $params->{DEFAULT_EDITOR} : 'vi';
75 7         19 my $status;
76             my @errs;
77             # new in 2020, support for VISUAL !!
78 7         23 for my $editor ($ENV{VISUAL}, $ENV{EDITOR}, $ed) {
79 21 100       56 next unless length $editor;
80 10         91 my @cmd = (shellwords($editor), $filename);
81 10         1060 $status = system { $cmd[0] } @cmd;
  10         21959  
82 10 100       322 if ($status != 0) {
83 8 100       391 push @errs,
84             ($status != -1)
85             ? "external editor failed: editor=$editor, errstr=$?"
86             : "could not launch program: editor=$editor, errstr=$!";
87             } else {
88 2         57 last;
89             }
90             }
91 7 100       54 if ($status != 0) {
92 5         72 $errstr = join ' ', @errs;
93 5         192 return;
94             }
95              
96             # Must reopen filename; the editor could pull a rename(2) on us, in
97             # which case $tfh is now invalid.
98 2         28 my $outfh;
99 2 50       171 unless (open($outfh, '<', $filename)) {
100 0         0 $errstr = "could not reopen tmp file: errstr=$!";
101 0         0 return;
102             }
103              
104 2 50       201 return wantarray ? ($outfh, $filename) : $outfh;
105             }
106              
107             # Perl CookBook code to check whether terminal is interactive
108             sub _is_interactive {
109 0     0     my $tty;
110 0 0         unless (open $tty, '<', '/dev/tty') {
111 0           $errstr = "cannot open /dev/tty: errno=$!";
112 0           return;
113             }
114 0           my $tpgrp = tcgetpgrp fileno $tty;
115 0           my $pgrp = getpgrp();
116 0           close $tty;
117 0 0         unless ($tpgrp == $pgrp) {
118 0           $errstr = "no exclusive control of tty: pgrp=$pgrp, tpgrp=$tpgrp";
119 0           return;
120             }
121 0           return 1;
122             }
123              
124             1;
125             __END__