1
package Padre::Task::Diff;
8
use Algorithm::Diff ();
10
use File::Basename ();
15
use Padre::Logger qw(TRACE);
17
our $VERSION = '0.92';
18
our @ISA = 'Padre::Task';
20
######################################################################
24
my $self = shift->SUPER::new(@_);
26
# Just convert the document to text for now.
27
# Later, we'll suck in more data from the project and
28
# other related documents to do differences calculation more awesomely.
29
unless ( Params::Util::_INSTANCE( $self->{document}, 'Padre::Document' ) ) {
30
die "Failed to provide a document to the diff task\n";
33
# Remove the document entirely as we do this,
34
# as it won't be able to survive serialisation.
35
my $document = delete $self->{document};
37
# Obtain document full filename
38
my $file = $document->{file};
39
$self->{filename} = $file ? $file->filename : undef;
41
# Obtain project's Version Control System (VCS)
42
$self->{vcs} = $document->project->vcs;
44
# Obtain document text
45
$self->{text} = $document->text_get;
47
# Obtain document encoding scheme
48
$self->{encoding} = $document->encoding;
50
# Obtain document project dir
51
$self->{project_dir} = $document->project_dir;
60
######################################################################
66
# Pull the text off the task so we won't need to serialize
67
# it back up to the parent Wx thread at the end of the task.
68
my $text = delete $self->{text};
69
my $vcs = delete $self->{vcs};
70
my $filename = delete $self->{filename};
71
my $project_dir = delete $self->{project_dir};
72
my $encoding = delete $self->{encoding};
74
# Compare between VCS and local buffer document
76
$data = $self->_find_vcs_diff( $vcs, $project_dir, $filename, $text, $encoding ) if $vcs;
79
# Compare between saved and current buffer document
80
$data = $self->_find_local_diff( $text, $filename, $encoding );
82
$self->{data} = $data;
87
# Find local differences between current unsaved document and saved document
88
sub _find_local_diff {
89
my ( $self, $text, $filename, $encoding ) = @_;
91
my $content = $filename ? _slurp( $filename, $encoding ) : undef;
93
if ( $content and $text ) {
94
$data = $self->_find_diffs( $$content, $text );
100
# Find differences between VCS versioned document and current document
102
my ( $self, $vcs, $project_dir, $filename, $text, $encoding ) = @_;
104
return $self->_find_svn_diff( $filename, $text, $encoding ) if $vcs eq Padre::Constant::SUBVERSION;
105
return $self->_find_git_diff( $project_dir, $filename, $text, $encoding ) if $vcs eq Padre::Constant::GIT;
107
#TODO implement the rest of the VCS like mercurial, bazaar
108
TRACE("Unhandled $vcs") if DEBUG;
113
# Generate a fast diff between the editor buffer and the original
114
# file in the .svn folder
115
# Contributed by submersible_toaster
117
my ( $self, $filename, $text, $encoding ) = @_;
119
my $local_cheat = File::Spec->catfile(
120
File::Basename::dirname($filename),
122
File::Basename::basename($filename) . '.svn-base'
124
my $origin = _slurp( $local_cheat, $encoding );
125
return $origin ? $self->_find_diffs( $$origin, $text ) : undef;
128
# Reads the contents of a file, and decode it using document encoding scheme
130
my ( $file, $encoding ) = @_;
132
open my $fh, '<', $file or return '';
139
$content = Encode::decode( $encoding, $content );
144
# Find differences between git versioned document and current document
146
my ( $self, $project_dir, $filename, $text, $encoding ) = @_;
148
# Create a temporary file for standard output redirection
149
my $out = File::Temp->new( UNLINK => 1 );
152
# Create a temporary file for standard error redirection
153
my $err = File::Temp->new( UNLINK => 1 );
156
# Find the git command line
157
my $git = File::Which::which('git') or return;
159
# Handle spaces in git executable path under win32
160
$git = qq{"$git"} if Padre::Constant::WIN32;
162
# 'git --no-pager show' command
163
my $path = File::Spec->abs2rel( $filename, $project_dir );
164
$path =~ s/\\/\//g if Padre::Constant::WIN32;
170
'1>' . $out->filename,
171
'2>' . $err->filename,
174
# We need shell redirection (list context does not give that)
175
# Run command in directory
176
Padre::Util::run_in_directory( join( ' ', @cmd ), $project_dir );
178
# Slurp git command standard input and output
179
my $stdout = _slurp( $out->filename, $encoding );
180
my $stderr = _slurp( $err->filename, $encoding );
182
if ( defined($stderr) and ( $$stderr eq '' ) and defined($stdout) ) {
183
return $self->_find_diffs( $$stdout, $text );
189
# Find differences between original text and unsaved text
191
my ( $self, $original_text, $unsaved_text ) = @_;
193
my @original_seq = split /^/, $original_text;
194
my @unsaved_seq = split /^/, $unsaved_text;
195
my @diff = Algorithm::Diff::diff( \@original_seq, \@unsaved_seq );
201
# Copyright 2008-2011 The Padre development team as listed in Padre.pm.
203
# This program is free software; you can redistribute it and/or
204
# modify it under the same terms as Perl 5 itself.