Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F3295541
PhabricatorDifferenceEngine.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
6 KB
Referenced Files
None
Subscribers
None
PhabricatorDifferenceEngine.php
View Options
<?php
/**
* Utility class which encapsulates some shared behavior between different
* applications which render diffs.
*
* @task config Configuring the Engine
* @task diff Generating Diffs
*/
final
class
PhabricatorDifferenceEngine
extends
Phobject
{
private
$oldName
;
private
$newName
;
private
$normalize
;
/* -( Configuring the Engine )--------------------------------------------- */
/**
* Set the name to identify the old file with. Primarily cosmetic.
*
* @param string $old_name Old file name.
* @return $this
* @task config
*/
public
function
setOldName
(
$old_name
)
{
$this
->
oldName
=
$old_name
;
return
$this
;
}
/**
* Set the name to identify the new file with. Primarily cosmetic.
*
* @param string $new_name New file name.
* @return $this
* @task config
*/
public
function
setNewName
(
$new_name
)
{
$this
->
newName
=
$new_name
;
return
$this
;
}
public
function
setNormalize
(
$normalize
)
{
$this
->
normalize
=
$normalize
;
return
$this
;
}
public
function
getNormalize
(
)
{
return
$this
->
normalize
;
}
/* -( Generating Diffs )--------------------------------------------------- */
/**
* Generate a raw diff from two raw files. This is a lower-level API than
* @{method:generateChangesetFromFileContent}, but may be useful if you need
* to use a custom parser configuration, as with Diffusion.
*
* @param string $old Entire previous file content.
* @param string $new Entire current file content.
* @return string Raw diff between the two files.
* @task diff
*/
public
function
generateRawDiffFromFileContent
(
$old
,
$new
)
{
$options
=
array
(
)
;
// Generate diffs with full context.
$options
[
]
=
'-U65535'
;
$old_name
=
nonempty
(
$this
->
oldName
,
'/dev/universe'
)
.
' 9999-99-99'
;
$new_name
=
nonempty
(
$this
->
newName
,
'/dev/universe'
)
.
' 9999-99-99'
;
$options
[
]
=
'-L'
;
$options
[
]
=
$old_name
;
$options
[
]
=
'-L'
;
$options
[
]
=
$new_name
;
$normalize
=
$this
->
getNormalize
(
)
;
if
(
$normalize
)
{
$old
=
$this
->
normalizeFile
(
$old
)
;
$new
=
$this
->
normalizeFile
(
$new
)
;
}
$old_tmp
=
new
TempFile
(
)
;
$new_tmp
=
new
TempFile
(
)
;
Filesystem
::
writeFile
(
$old_tmp
,
$old
)
;
Filesystem
::
writeFile
(
$new_tmp
,
$new
)
;
list
(
$err
,
$diff
)
=
exec_manual
(
'diff %Ls %s %s'
,
$options
,
$old_tmp
,
$new_tmp
)
;
if
(
!
$err
)
{
// This indicates that the two files are the same. Build a synthetic,
// changeless diff so that we can still render the raw, unchanged file
// instead of being forced to just say "this file didn't change" since we
// don't have the content.
$entire_file
=
explode
(
"\n"
,
$old
)
;
foreach
(
$entire_file
as
$k
=>
$line
)
{
$entire_file
[
$k
]
=
' '
.
$line
;
}
$len
=
count
(
$entire_file
)
;
$entire_file
=
implode
(
"\n"
,
$entire_file
)
;
// TODO: If both files were identical but missing newlines, we probably
// get this wrong. Unclear if it ever matters.
// This is a bit hacky but the diff parser can handle it.
$diff
=
"--- {$old_name}\n"
.
"+++ {$new_name}\n"
.
"@@ -1,{$len} +1,{$len} @@\n"
.
$entire_file
.
"\n"
;
}
return
$diff
;
}
/**
* Generate an @{class:DifferentialChangeset} from two raw files. This is
* principally useful because you can feed the output to
* @{class:DifferentialChangesetParser} in order to render it.
*
* @param string $old Entire previous file content.
* @param string $new Entire current file content.
* @return @{class:DifferentialChangeset} Synthetic changeset.
* @task diff
*/
public
function
generateChangesetFromFileContent
(
$old
,
$new
)
{
$diff
=
$this
->
generateRawDiffFromFileContent
(
$old
,
$new
)
;
$changes
=
id
(
new
ArcanistDiffParser
(
)
)
->
parseDiff
(
$diff
)
;
$diff
=
DifferentialDiff
::
newEphemeralFromRawChanges
(
$changes
)
;
return
head
(
$diff
->
getChangesets
(
)
)
;
}
private
function
normalizeFile
(
$corpus
)
{
// We can freely apply any other transformations we want to here: we have
// no constraints on what we need to preserve. If we normalize every line
// to "cat", the diff will still work, the alignment of the "-" / "+"
// lines will just be very hard to read.
// In general, we'll make the diff better if we normalize two lines that
// humans think are the same.
// We'll make the diff worse if we normalize two lines that humans think
// are different.
// Strip all whitespace present anywhere in the diff, since humans never
// consider whitespace changes to alter the line into a "different line"
// even when they're semantic (e.g., in a string constant). This covers
// indentation changes, trailing whitepspace, and formatting changes
// like "+/-".
$corpus
=
preg_replace
(
'/[ \t]/'
,
''
,
$corpus
)
;
return
$corpus
;
}
public
static
function
applyIntralineDiff
(
$str
,
$intra_stack
)
{
$buf
=
''
;
$p
=
$s
=
$e
=
0
;
// position, start, end
$highlight
=
$tag
=
$ent
=
false
;
$highlight_o
=
'<span class="bright">'
;
$highlight_c
=
'</span>'
;
$depth_in
=
'<span class="depth-in">'
;
$depth_out
=
'<span class="depth-out">'
;
$is_html
=
false
;
if
(
$str
instanceof
PhutilSafeHTML
)
{
$is_html
=
true
;
$str
=
$str
->
getHTMLContent
(
)
;
}
$n
=
strlen
(
$str
)
;
for
(
$i
=
0
;
$i
<
$n
;
$i
++
)
{
if
(
$p
==
$e
)
{
do
{
if
(
empty
(
$intra_stack
)
)
{
$buf
.=
substr
(
$str
,
$i
)
;
break
2
;
}
$stack
=
array_shift
(
$intra_stack
)
;
$s
=
$e
;
$e
+=
$stack
[
1
]
;
}
while
(
$stack
[
0
]
===
0
)
;
switch
(
$stack
[
0
]
)
{
case
'>'
:
$open_tag
=
$depth_in
;
break
;
case
'<'
:
$open_tag
=
$depth_out
;
break
;
default
:
$open_tag
=
$highlight_o
;
break
;
}
}
if
(
!
$highlight
&&
!
$tag
&&
!
$ent
&&
$p
==
$s
)
{
$buf
.=
$open_tag
;
$highlight
=
true
;
}
if
(
$str
[
$i
]
==
'<'
)
{
$tag
=
true
;
if
(
$highlight
)
{
$buf
.=
$highlight_c
;
}
}
if
(
!
$tag
)
{
if
(
$str
[
$i
]
==
'&'
)
{
$ent
=
true
;
}
if
(
$ent
&&
$str
[
$i
]
==
';'
)
{
$ent
=
false
;
}
if
(
!
$ent
)
{
$p
++
;
}
}
$buf
.=
$str
[
$i
]
;
if
(
$tag
&&
$str
[
$i
]
==
'>'
)
{
$tag
=
false
;
if
(
$highlight
)
{
$buf
.=
$open_tag
;
}
}
if
(
$highlight
&&
(
$p
==
$e
||
$i
==
$n
-
1
)
)
{
$buf
.=
$highlight_c
;
$highlight
=
false
;
}
}
if
(
$is_html
)
{
return
phutil_safe_html
(
$buf
)
;
}
return
$buf
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Thu, Mar 27, 02:24 (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1142489
Default Alt Text
PhabricatorDifferenceEngine.php (6 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment