Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1307
Annotation.php
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Authored By
•
bzimport
Nov 21 2014, 6:56 PM
2014-11-21 18:56:17 (UTC+0)
Size
8 KB
Referenced Files
None
Subscribers
None
Annotation.php
View Options
<?php
/**
* Defines Annotation object to implement annotate/blame functionality
*
* An Annotation is an array of ExtendedStrings. Both Annotation and
* ExtendedStrings must act like regular strings, but their sets of
* functionality vary. An ExtendedString must be able to be chopped up without
* damaging information. An Annotation must be able to have segments of text
* deleted, added or modified while keeping track of all the ExtendedStrings,
* chopping up them if necessary. RevisionInfo is a parameter object that
* contains the interesting information that regular strings don't have.
*/
/**
* A regular string that has RevisionInfo. Automatically normalizes newlines.
*/
class
ExtendedString
{
var
$string
;
var
$revision_info
;
function
ExtendedString
(
$string
,
$revision_info
)
{
$this
->
string
=
str_replace
(
"
\r\n
"
,
"
\n
"
,
$string
);
$this
->
revision_info
=
$revision_info
;
}
function
newFromArray
(
$array
,
$revision_info
)
{
if
(!
is_array
(
$array
))
return
null
;
return
new
ExtendedString
(
implode
(
$array
,
''
),
$revision_info
);
}
function
strlen
()
{
return
strlen
(
$this
->
string
);
}
function
substr
(
$start
,
$length
=
null
)
{
if
(
$length
===
null
)
{
$string
=
substr
(
$this
->
string
,
$start
);
}
else
{
$string
=
substr
(
$this
->
string
,
$start
,
$length
);
}
return
new
ExtendedString
(
$string
,
$this
->
revision_info
);
}
function
append
(
$string
)
{
$this
->
string
.=
$string
;
}
function
splitAt
(
$position
)
{
return
array
(
new
ExtendedString
(
substr
(
$this
->
string
,
0
,
$position
),
$this
->
revision_info
),
new
ExtendedString
(
substr
(
$this
->
string
,
$position
),
$this
->
revision_info
)
);
}
}
/**
* This string is used to show that something was deleted here
*/
class
PhantomString
extends
ExtendedString
{
var
$phantom
=
true
;
function
PhantomString
(
$revision_info
)
{
$this
->
ExtendedString
(
''
,
$revision_info
);
}
function
strlen
()
{
return
0
;}
function
substr
()
{
return
new
PhantomString
(
$this
->
revision_info
);}
function
append
()
{}
function
splitAt
()
{
return
array
();}
}
/**
* Indicates something was deleted here in the specified revision.
*/
class
DeletionMark
{
var
$revision_info
;
}
/**
* Specifies extra authorship information, such as the user and the ID of it
*/
class
RevisionInfo
{
var
$id
;
var
$user
;
var
$user_text
;
var
$timestamp
;
var
$minor_edit
;
function
RevisionInfo
(
$id
,
$user
,
$user_text
,
$timestamp
,
$minor_edit
)
{
$this
->
id
=
$id
;
$this
->
user
=
$user
;
$this
->
user_text
=
$user_text
;
$this
->
timestamp
=
$timestamp
;
$this
->
minor_edit
=
$minor_edit
;
}
}
class
UnknownRevisionInfo
{
var
$unknown
=
true
;
function
UnknownRevisionInfo
()
{}
}
/**
* Represents a string, but keeps track of RevisionInfo. Has diffs applied to
* it.
*/
class
Annotation
{
var
$strings
;
var
$ac
=
0
;
var
$sc
=
0
;
function
Annotation
(
$strings
=
array
(),
$positions
=
array
(
0
,
0
))
{
$this
->
strings
=
$strings
;
//expects an array of ExtendedString objects
list
(
$this
->
ac
,
$this
->
sc
)
=
$positions
;
}
function
copy
(
$distance
,
$extended_string
=
null
)
{
//scroll ahead specified distance
//loop iterates each time we advance one element in the array
for
(
// i represents the string, as we scroll ahead, we chop off bits of
// the string until nothing is left
$i
=
$distance
;
// every iteration, we check that there is stil is string left, and
// do a sanity check, making sure that our entry exists
$i
>
0
&&
isset
(
$this
->
strings
[
$this
->
ac
]);
// an iteration represents scrolling forward in the array, resetting
// the string counter
$this
->
ac
++,
$this
->
sc
=
0
)
{
$length
=
$this
->
strings
[
$this
->
ac
]->
strlen
()
-
$this
->
sc
;
if
(
$length
>
$i
)
{
// we have to break it up, since the distance can't get
// all the way across
$new_strings
=
$this
->
strings
[
$this
->
ac
]->
splitAt
(
$i
);
array_splice
(
$this
->
strings
,
$this
->
ac
,
1
,
$new_strings
);
}
$i
-=
$length
;
}
//fix extra possible addition to extended_string
if
(
$extended_string
!==
null
&&
$distance
!=
$extended_string
->
strlen
())
{
$extra
=
$extended_string
->
substr
(
$distance
);
$extra
=
$extra
->
string
;
$this
->
strings
[
$this
->
ac
-
1
]->
append
(
$extra
);
}
}
function
add
(
$extended_string
)
{
//scroll past all phantom strings before inserting
while
(
isset
(
$this
->
strings
[
$this
->
ac
]->
phantom
))
$this
->
ac
++;
array_splice
(
$this
->
strings
,
$this
->
ac
++,
0
,
array
(
$extended_string
)
);
}
function
delete
(
$distance
,
$revision_info
)
{
// loop is similar to structure as copy, it just has different meat
for
(
$i
=
$distance
;
$i
>
0
&&
isset
(
$this
->
strings
[
$this
->
ac
]);
//ac does not get reset because we just shifted the array
$this
->
sc
=
0
)
{
// sc expected to be 0, too lazy to write defense code
$length
=
$this
->
strings
[
$this
->
ac
]->
strlen
();
if
(
$i
<
$length
)
{
$array
=
array
();
if
(
$revision_info
!==
false
)
{
$array
[]
=
new
PhantomString
(
$revision_info
);
}
$array
[]
=
$this
->
strings
[
$this
->
ac
]->
substr
(
$i
);
array_splice
(
$this
->
strings
,
$this
->
ac
,
1
,
$array
);
}
else
{
array_splice
(
$this
->
strings
,
$this
->
ac
,
1
);
}
$i
-=
$length
;
}
if
(
$i
==
0
&&
$revision_info
!==
false
)
{
//ahh, it finished perfectly, so no phantom was added
$this
->
add
(
new
PhantomString
(
$revision_info
));
}
}
function
change
(
$distance
,
$extended_string
)
{
$this
->
delete
(
$distance
,
false
);
$this
->
add
(
$extended_string
);
}
function
newFromRevisions
(
$strings
)
{
require_once
(
'DifferenceEngine.php'
);
$annotation
=
new
Annotation
();
$num_diffs
=
count
(
$strings
)
-
1
;
for
(
$i
=
0
;
$i
<
$num_diffs
;
$i
++)
{
$annotation
->
reset
();
if
(
$i
==
0
)
{
//this is the first iteration, load up annotation
$annotation
->
strings
[]
=
$strings
[
$i
];
}
//get the diff
$ota
=
explode
(
"
\n
"
,
str_replace
(
"
\r\n
"
,
"
\n
"
,
$strings
[
$i
]->
string
));
$nta
=
explode
(
"
\n
"
,
str_replace
(
"
\r\n
"
,
"
\n
"
,
$strings
[
$i
+
1
]->
string
));
$diff
=
new
WordLevelDiff
(
$ota
,
$nta
);
$edits
=
$diff
->
edits
;
$info
=
$strings
[
$i
+
1
]->
revision_info
;
foreach
(
$edits
as
$edit
)
{
$orig
=
ExtendedString
::
newFromArray
(
$edit
->
orig
,
$info
);
$closing
=
ExtendedString
::
newFromArray
(
$edit
->
closing
,
$info
);
switch
(
$edit
->
type
)
{
case
'copy'
:
$annotation
->
copy
(
$orig
->
strlen
(),
$closing
);
break
;
case
'add'
:
$annotation
->
add
(
$closing
);
break
;
case
'delete'
:
$annotation
->
delete
(
$orig
->
strlen
());
break
;
case
'change'
:
$annotation
->
change
(
$orig
->
strlen
(),
$closing
);
break
;
default
:
exit
;
}
}
}
$annotation
->
reset
();
return
$annotation
;
}
function
reset
()
{
$this
->
ac
=
$this
->
sc
=
0
;}
function
clump
()
{}
}
?>
File Metadata
Details
Attached
Mime Type
text/x-php
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1206
Default Alt Text
Annotation.php (8 KB)
Attached To
Mode
T2639: [Epic] Add feature annotate/blame command, to indicate who last changed each line / word
Attached
Detach File
Event Timeline
Log In to Comment