Proc-InvokeEditor-1.07/0000700000175000017500000000000012367766033015241 5ustar mstevensmstevensProc-InvokeEditor-1.07/Changes0000644000175000017500000000146112367765670016556 0ustar mstevensmstevensRevision history for Perl extension Proc::InvokeEditor. 0.01_01 Mon Aug 27 14:08:09 2001 - original version; created by h2xs 1.21 with options -X -A -m Proc::InvokeEditor -v 0.01_01 -b 5.005_03 0.01_02 Mon Aug 27 16:50 2001 - new version, incorporate feedback so $EDITOR = 'xemacs -nw' works, added more error checking when looping through editors , added editors_env and editors_prepend. 1.01 13 Mar 2007 - Increase CPANTS score. 1.02 16 Dec 2007 - Patches from Tim Booth tbooth@ceh.ac.uk to provide optional filename suffix option. 1.04 30 Jul 2010 - Add a "use warnings" to keep CPANTS happy. 1.05 19 Feb 2011 - Fix README 1.06 25 Apr 2011 - Apply patch from Jesse Luehrs to optionally reuse temp file names. 1.07 04 Aug 2014 - Apply patch from Brian Fraser to work on android. Proc-InvokeEditor-1.07/lib/0000700000175000017500000000000012367766033016007 5ustar mstevensmstevensProc-InvokeEditor-1.07/lib/Proc/0000700000175000017500000000000012367766033016712 5ustar mstevensmstevensProc-InvokeEditor-1.07/lib/Proc/InvokeEditor.pm0000644000175000017500000002463212367765625021701 0ustar mstevensmstevenspackage Proc::InvokeEditor; use strict; use warnings; use File::Temp qw(tempfile); use File::Spec; use IPC::Cmd qw(can_run); use Carp::Assert; use Fcntl; File::Temp->safe_level( File::Temp::HIGH ); require Exporter; use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION @DEFAULT_EDITORS); @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use Proc::InvokeEditor ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); @EXPORT = qw( ); $VERSION = '1.07'; @DEFAULT_EDITORS = ( $ENV{'VISUAL'}, $ENV{'EDITOR'}, '/usr/bin/vi', '/bin/vi', '/bin/ed', map({ can_run($_) } qw(vi ed)) ); sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = { 'editors' => \@DEFAULT_EDITORS, 'cleanup' => 1, 'keep_file' => 0, }; croak("$class requires an even number of parameters") if @_ % 2; my %args = @_; foreach my $param (qw(editors cleanup keep_file)) { if ($args{$param}) { $self->{$param} = $args{$param}; } } bless ($self, $class); return $self; } sub editors { my $self = shift; my $editors = shift; if (defined $editors) { assert(ref($editors) eq 'ARRAY'); $self->{'editors'} = $editors; } return $self->{'editors'}; } sub editors_prepend { my $self = shift; my $edit = shift; assert(ref($edit) eq 'ARRAY'); my @editors = @{$self->{'editors'}}; unshift @editors, @$edit; $self->{'editors'} = \@editors; } sub editors_env { my $self = shift; my $edit = shift; assert(ref($edit) eq 'ARRAY'); my @editors; if (@$edit) { foreach my $e (@$edit) { if (exists $ENV{$e} and defined $ENV{$e}) { push @editors, $ENV{$e}; } } my @editors_list = @{$self->{'editors'}}; unshift @editors_list, @editors; $self->{'editors'} = \@editors_list; } return $self->{'editors'}; } sub cleanup { my $self = shift; my $cleanup = shift; $self->{'cleanup'} = $cleanup if defined $cleanup; return $self->{'cleanup'}; } sub keep_file { my $self = shift; my $keep_file = shift; $self->{'keep_file'} = $keep_file if defined $keep_file; return $self->{'keep_file'}; } sub edit { my $self = shift; my $arg = shift; my $suff = shift; # if the argument supplied is a reference to an array of lines, # join it together based on the input record separator if (ref($arg) eq 'ARRAY') { $arg = join $/, @$arg; } my $result; if (ref($self)) { ($result, $self->{'filename'}) = _edit( $arg, $self->{'editors'}, $self->{'cleanup'}, $self->{'keep_file'}, $self->{'filename'}, $suff, ); } else { ($result) = _edit($arg, \@DEFAULT_EDITORS, 1, 0, undef, $suff); } if (wantarray) { my @result = split m|$/|, $result; return @result; } else { return $result; } } sub first_usable { my $self = shift; my $er = shift; my @editors; if (defined $er) { @editors = @$er; } else { if (ref $self) { @editors = @{$self->{'editors'}}; } else { @editors = @DEFAULT_EDITORS; } } my $chosen_editor; my @path = File::Spec->path; EDITORS: foreach my $editor (@editors) { next unless defined $editor; my @editor_bits = split /\s+/, $editor; next unless defined $editor_bits[0]; if (File::Spec->file_name_is_absolute($editor_bits[0]) and -x $editor_bits[0]) { $chosen_editor = \@editor_bits; last; } else { foreach my $dir (@path) { my $file = File::Spec->catfile($dir, $editor_bits[0]); if (-x $file) { $editor_bits[0] = $file; $chosen_editor = \@editor_bits; last EDITORS; } } } } die "Couldn't find an editor: $!" unless defined $chosen_editor; return $chosen_editor; } sub _edit { my $string = shift; my $er = shift; my $unlink = shift; my $keep_file = shift; my $filename = shift; my $suff = shift; assert(ref($er) eq 'ARRAY'); assert(defined $unlink); my @editors = @$er; # Find an editor my $chosen_editor = first_usable(undef, $er); my @suff; @suff = (SUFFIX => $suff) if $suff; # get a temp file, and write the text to it if (defined($filename) && $keep_file) { open my $fh, '>', $filename or die "Couldn't open tempfile [$filename]; $!"; print $fh $string; close $fh or die "Couldn't close tempfile [$filename]; $!"; } else { my $fh; ($fh, $filename) = tempfile(UNLINK => $unlink, @suff); print $fh $string; close $fh or die "Couldn't close tempfile [$filename]; $!"; } # start the editor my $rc = system @$chosen_editor, $filename; # check what happened - die if it all went wrong. unless ($rc == 0) { my ($exit_value, $signal_num, $dumped_core); $exit_value = $? >> 8; $signal_num = $? & 127; $dumped_core = $? & 128; die "Error in editor - exit val = $exit_value, signal = $signal_num, coredump? = $dumped_core: $!"; } # read the temp file sysopen(FH, $filename, O_RDONLY) or die "Couldn't sysopen $filename: $!"; my $result; { local $/; $result = ; } close FH or die "Couldn't close [$filename]: $!"; # return as string if ($keep_file) { return ($result, $filename); } else { return ($result); } } 1; __END__ =head1 NAME Proc::InvokeEditor - Perl extension for starting a text editor =head1 SYNOPSIS use Proc::InvokeEditor; my $edited_text = Proc::InvokeEditor->edit($unedited_text); =head1 DESCRIPTION This module provides the ability to supply some text to an external text editor, have it edited by the user, and retrieve the results. The File::Temp module is used to provide secure, safe temporary files, and File::Temp is set to its highest available level of security. This may cause problems on some systems where no secure temporary directory is available. When the editor is started, no subshell is used. Your path will be scanned to find the binary to use for each editor if the string given does not exist as a file, and if a named editor contains whitespace, eg) if you try to use the editor C, then the string will be split on whitespace and anything after the editor name will be passed as arguments to your editor. A shell is not used but this should cover most simple cases. =head1 METHODS =head2 new(editors => [ editor list ], cleanup => 1) This method creates a new Proc::InvokeEditor object. It takes two optional arguments in key => value form: =over 4 =item C This should be a reference to an array of possible editor filenames to use. Each editor listed will be tried in turn until a working editor is found. If this argument is not supplied, an internal default list will be used. =item C This specifies whether the temporary file created should be unlinked when the program exits. The default is to unlink the file. =item C This specifies whether to reuse the same temporary file between invocations of C on the same Proc::InvokeEditor object. The default is to use a new file each time. =back =head2 editors() This method gets or sets the list of editors to use. If no argument is supplied, it returns the current value from the object, if an argument is supplied, it changes the value and returns the new value. The argument should be a reference to a list of text editor filenames. =head2 editors_env($arrayref) Takes a reference to an array of C<%ENV> keys to use as possible editors. Each C<$ENV{$key}> value is only used if that key exits in C<%ENV> and the value is defined. The new values are prepended to the currently stored list of editors to use. =head2 editors_prepend($arrayref) Takes a reference to an array of editors to use, and prepends them to the currently stored list. =head2 cleanup() This method gets or sets whether to cleanup temporary files after the program exits. If no argument is supplied, it returns the current value from the object. If an argument is supplied, it changes the value and returns the new object. The argument should be any true or false value. =head2 keep_file() This method gets or sets whether to reuse temporary files. If no argument is supplied, it returns the current value from the object. If an argument is supplied, it changes the value and returns the new object. The argument should be any true or false value. =head2 first_usable() This method can be called either as a class method, in which it returns the first usable editor of the default list of editors, or as an object method, in which case it returns the first usable editor of the currently configured list. The return is a reference to an array, the first element of which is a filename, and the other elements of which are appropriate arguments to the the command. If this method can not find any usable editor, it will die. =head2 edit($unedited_text) This can be called as either a class method or an object method. When called as a class method, it starts an external text editor in the text supplied, and returns the result to you. The text to edit can be supplied either as a scalar, in which case it will be treated as a simple string, or as a reference to an array, in which case it will be treated as an array of lines. Example use of this form is as follows: my $result = Proc::InvokeEditor->edit($string); my @lines = Proc::InvokeEditor->edit(\@unedited_lines); my @lines = Proc::InvokeEditor->edit($string); When called as an object method, it behaves identically, but uses configuration parameters from the object: my $editor = new Proc::InvokeEditor(editors => [ '/usr/bin/emacs' ]); $editor->cleanup(0); my $result = $editor->edit($string); A optional second argument is available $suff - example usage: my $reuslt = Proc::InvokeEditor->edit($string, '.xml'); This specifies a filename suffix to be used when the editor is launched - this can be useful if the data in the file is of a particular type and you want to trigger an editor's syntax highlighting mode. =head1 TODO =over 4 =item * Write a test suite. =back =head1 AUTHOR Michael Stevens Emstevens@etla.orgE. Also incorporating suggestions and feedback from Leon Brocard and Phil Pennock. Patches supplied by Tim Booth. =head1 SEE ALSO L. =cut Proc-InvokeEditor-1.07/README0000644000175000017500000000171112367765724016141 0ustar mstevensmstevensProc::InvokeEditor version 1.07 ======================= This module provides a simple API to calling an external text editor from within your perl program. This is a trivial task, but there are potential security issues if you don't get it right, and it's fundamentally tedious to write any piece of code more than once. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install During the testing process Proc::InvokeEditor will attempt to start a text editor for testing. Please save the files opened immediately with no changes. DEPENDENCIES This module requires these other modules and libraries: * File::Temp * Test::More * Carp::Assert * File::Spec * IPC::Cmd REPOSITORY This module lives on github at: http://github.com/mstevens/Proc--InvokeEditor COPYRIGHT AND LICENCE This module is licensed under the same terms as Perl itself. Copyright (C) 2001,2010,2011,2014 Michael Stevens and others Proc-InvokeEditor-1.07/META.yml0000600000175000017500000000122712367766033016516 0ustar mstevensmstevens--- #YAML:1.0 name: Proc-InvokeEditor version: 1.07 abstract: Interface to external editor from perl author: - Michael Stevens license: perl distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: Carp::Assert: 0.11 File::Spec: 0.82 File::Temp: 0.12 IPC::Cmd: 0 Test::More: 0.08 no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.57_05 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 Proc-InvokeEditor-1.07/Makefile.PL0000644000175000017500000000154012367765602017226 0ustar mstevensmstevensuse ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Proc::InvokeEditor', 'VERSION_FROM' => 'lib/Proc/InvokeEditor.pm', # finds $VERSION 'PREREQ_PM' => { 'File::Temp' => 0.12, 'Test::More' => 0.08, 'Carp::Assert' => 0.11, 'File::Spec' => 0.82, 'IPC::Cmd' => 0, }, # e.g., Module::Name => 1.1 'dist' => { 'COMPRESS' => 'gzip -9f', 'SUFFIX' => 'gz', }, ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT => 'Interface to external editor from perl', AUTHOR => 'Michael Stevens ') : ()), 'LICENSE' => 'perl', ); Proc-InvokeEditor-1.07/examples/0000700000175000017500000000000012367766033017057 5ustar mstevensmstevensProc-InvokeEditor-1.07/examples/example2.pl0000644000175000017500000000105111530024325021116 0ustar mstevensmstevens#!/usr/local/bin/perl -w use strict; use Proc::InvokeEditor; my $editor = new Proc::InvokeEditor(editors => [ '/usr/bin/emacs' ]); my $e = $editor->first_usable; print "Usable = " . $e->[0] . "\n"; my @result = $editor->edit("foo\nbar\nbaz\n"); foreach my $line (@result) { print "Line: $line\n"; } sleep 5; $editor->editors(['/usr/bin/vi']); $editor->editors_prepend(['/bin/ed']); $editor->editors_env(['TURNIP']); my $result = $editor->edit("something\nin\nvi\n"); print $result; $e = $editor->first_usable; print "Usable = " . $e->[0] . "\n"; Proc-InvokeEditor-1.07/examples/example.pl0000644000175000017500000000033411530024325021037 0ustar mstevensmstevens#!/usr/local/bin/perl -w use strict; use Proc::InvokeEditor; my @result = Proc::InvokeEditor->edit("foo\nbar\nbaz\n"); use Data::Dumper; print Dumper(@result); foreach my $line (@result) { print "Line: $line\n"; } Proc-InvokeEditor-1.07/t/0000700000175000017500000000000012367766033015504 5ustar mstevensmstevensProc-InvokeEditor-1.07/t/01_require.t0000644000175000017500000000015411530024325017635 0ustar mstevensmstevens#!/usr/local/bin/perl -w use strict; use Test::More tests => 1; BEGIN { use_ok('Proc::InvokeEditor'); } Proc-InvokeEditor-1.07/t/02_editor.t0000644000175000017500000000262311530024325017453 0ustar mstevensmstevens#!/usr/local/bin/perl -w use strict; use Proc::InvokeEditor; use Test::More tests => 8; # create a new object? my $e = new Proc::InvokeEditor; ok(defined($e), 'Object created'); is(ref($e), 'Proc::InvokeEditor', 'Object type correct'); # set and get editors $e->editors(['vi', 'emacs', 'ed']); my $editors = $e->editors; ok(eq_array($editors, ['vi', 'emacs', 'ed']), 'can set editors'); # set and get cleanup $e->cleanup(1); my $cleanup = $e->cleanup; is($cleanup, 1, 'Cleanup can be set'); # prepend something to editors, see if it works $e->editors_prepend(['vim']); $editors = $e->editors; ok(eq_array($editors, ['vim', 'vi', 'emacs', 'ed']), 'can prepend'); # can prepend env $ENV{FOO} = 'x'; $ENV{BAR} = 'y'; $e->editors_env(['FOO', 'BAR']); $editors = $e->editors; ok(eq_array($editors, ['x', 'y', 'vim', 'vi', 'emacs', 'ed']), 'can env prepend'); # can we find any first usable editor? my $f = Proc::InvokeEditor->first_usable; ok(defined $f, 'first usable editor was defined'); is(ref($f), 'ARRAY', 'usable editor was an array'); #my $templ = "PLEASE SAVE THIS FILE WITHOUT CHANGES\n"; #my $edited_text = Proc::InvokeEditor->edit($templ); #is($edited_text, $templ, "template saved unchanged successfully"); #my @templ_lines = ("PLEASE SAVE THIS", "WITH NO CHANGES"); #my @edit_lines = Proc::InvokeEditor->edit(\@templ_lines); #ok(eq_array(\@templ_lines, \@edit_lines), 'array template saved unchanged fine'); # Proc-InvokeEditor-1.07/t/03_pod.t0000644000175000017500000000020111530024325016736 0ustar mstevensmstevensuse Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Proc-InvokeEditor-1.07/t/04_pod_coverage.t0000644000175000017500000000024111530024325020616 0ustar mstevensmstevensuse Test::More; eval "use Test::Pod::Coverage 1.00"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; all_pod_coverage_ok(); Proc-InvokeEditor-1.07/LICENSE0000644000175000017500000000007511530024325016240 0ustar mstevensmstevensThis module is released under the same terms as perl itself. Proc-InvokeEditor-1.07/MANIFEST0000644000175000017500000000037112367765563016414 0ustar mstevensmstevensChanges lib/Proc/InvokeEditor.pm Makefile.PL MANIFEST LICENSE README t/01_require.t t/02_editor.t t/03_pod.t t/04_pod_coverage.t examples/example.pl examples/example2.pl META.yml Module meta-data (added by MakeMaker)