Merge branch 'master' into blender-tweaks
This commit is contained in:
@@ -9,7 +9,7 @@ return array(
|
|||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => '3c8a0668',
|
'conpherence.pkg.css' => '3c8a0668',
|
||||||
'conpherence.pkg.js' => '020aebcf',
|
'conpherence.pkg.js' => '020aebcf',
|
||||||
'core.pkg.css' => '4451f9fd',
|
'core.pkg.css' => 'f8c53b6f',
|
||||||
'core.pkg.js' => '6e5c894f',
|
'core.pkg.js' => '6e5c894f',
|
||||||
'differential.pkg.css' => '607c84be',
|
'differential.pkg.css' => '607c84be',
|
||||||
'differential.pkg.js' => 'a0212a0b',
|
'differential.pkg.js' => 'a0212a0b',
|
||||||
@@ -169,7 +169,7 @@ return array(
|
|||||||
'rsrc/css/phui/phui-pager.css' => 'd022c7ad',
|
'rsrc/css/phui/phui-pager.css' => 'd022c7ad',
|
||||||
'rsrc/css/phui/phui-pinboard-view.css' => '1f08f5d8',
|
'rsrc/css/phui/phui-pinboard-view.css' => '1f08f5d8',
|
||||||
'rsrc/css/phui/phui-policy-section-view.css' => '139fdc64',
|
'rsrc/css/phui/phui-policy-section-view.css' => '139fdc64',
|
||||||
'rsrc/css/phui/phui-property-list-view.css' => 'ad841f1c',
|
'rsrc/css/phui/phui-property-list-view.css' => '807b1632',
|
||||||
'rsrc/css/phui/phui-remarkup-preview.css' => '91767007',
|
'rsrc/css/phui/phui-remarkup-preview.css' => '91767007',
|
||||||
'rsrc/css/phui/phui-segment-bar-view.css' => '5166b370',
|
'rsrc/css/phui/phui-segment-bar-view.css' => '5166b370',
|
||||||
'rsrc/css/phui/phui-spacing.css' => 'b05cadc3',
|
'rsrc/css/phui/phui-spacing.css' => 'b05cadc3',
|
||||||
@@ -868,7 +868,7 @@ return array(
|
|||||||
'phui-pager-css' => 'd022c7ad',
|
'phui-pager-css' => 'd022c7ad',
|
||||||
'phui-pinboard-view-css' => '1f08f5d8',
|
'phui-pinboard-view-css' => '1f08f5d8',
|
||||||
'phui-policy-section-view-css' => '139fdc64',
|
'phui-policy-section-view-css' => '139fdc64',
|
||||||
'phui-property-list-view-css' => 'ad841f1c',
|
'phui-property-list-view-css' => '807b1632',
|
||||||
'phui-remarkup-preview-css' => '91767007',
|
'phui-remarkup-preview-css' => '91767007',
|
||||||
'phui-segment-bar-view-css' => '5166b370',
|
'phui-segment-bar-view-css' => '5166b370',
|
||||||
'phui-spacing-css' => 'b05cadc3',
|
'phui-spacing-css' => 'b05cadc3',
|
||||||
|
|||||||
@@ -3140,6 +3140,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorDivinerApplication' => 'applications/diviner/application/PhabricatorDivinerApplication.php',
|
'PhabricatorDivinerApplication' => 'applications/diviner/application/PhabricatorDivinerApplication.php',
|
||||||
'PhabricatorDocumentEngine' => 'applications/files/document/PhabricatorDocumentEngine.php',
|
'PhabricatorDocumentEngine' => 'applications/files/document/PhabricatorDocumentEngine.php',
|
||||||
'PhabricatorDocumentEngineBlock' => 'applications/files/diff/PhabricatorDocumentEngineBlock.php',
|
'PhabricatorDocumentEngineBlock' => 'applications/files/diff/PhabricatorDocumentEngineBlock.php',
|
||||||
|
'PhabricatorDocumentEngineBlockDiff' => 'applications/files/diff/PhabricatorDocumentEngineBlockDiff.php',
|
||||||
'PhabricatorDocumentEngineBlocks' => 'applications/files/diff/PhabricatorDocumentEngineBlocks.php',
|
'PhabricatorDocumentEngineBlocks' => 'applications/files/diff/PhabricatorDocumentEngineBlocks.php',
|
||||||
'PhabricatorDocumentRef' => 'applications/files/document/PhabricatorDocumentRef.php',
|
'PhabricatorDocumentRef' => 'applications/files/document/PhabricatorDocumentRef.php',
|
||||||
'PhabricatorDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorDocumentRenderingEngine.php',
|
'PhabricatorDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorDocumentRenderingEngine.php',
|
||||||
@@ -9481,6 +9482,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorDivinerApplication' => 'PhabricatorApplication',
|
'PhabricatorDivinerApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorDocumentEngine' => 'Phobject',
|
'PhabricatorDocumentEngine' => 'Phobject',
|
||||||
'PhabricatorDocumentEngineBlock' => 'Phobject',
|
'PhabricatorDocumentEngineBlock' => 'Phobject',
|
||||||
|
'PhabricatorDocumentEngineBlockDiff' => 'Phobject',
|
||||||
'PhabricatorDocumentEngineBlocks' => 'Phobject',
|
'PhabricatorDocumentEngineBlocks' => 'Phobject',
|
||||||
'PhabricatorDocumentRef' => 'Phobject',
|
'PhabricatorDocumentRef' => 'Phobject',
|
||||||
'PhabricatorDocumentRenderingEngine' => 'Phobject',
|
'PhabricatorDocumentRenderingEngine' => 'Phobject',
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ final class Aphront403Response extends AphrontHTMLResponse {
|
|||||||
$dialog = id(new AphrontDialogView())
|
$dialog = id(new AphrontDialogView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setTitle(pht('403 Forbidden'))
|
->setTitle(pht('403 Forbidden'))
|
||||||
->addCancelButton('/', pht('Peace Out'))
|
->addCancelButton('/', pht('Yikes!'))
|
||||||
->appendParagraph($forbidden_text);
|
->appendParagraph($forbidden_text);
|
||||||
|
|
||||||
$view = id(new PhabricatorStandardPageView())
|
$view = id(new PhabricatorStandardPageView())
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
return $this->depthOnlyLines;
|
return $this->depthOnlyLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setVisibileLinesMask(array $mask) {
|
public function setVisibleLinesMask(array $mask) {
|
||||||
$this->visible = $mask;
|
$this->visible = $mask;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -699,13 +699,13 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
$lines_context = $this->getLinesOfContext();
|
$lines_context = $this->getLinesOfContext();
|
||||||
|
|
||||||
$hunk_parser->generateIntraLineDiffs();
|
$hunk_parser->generateIntraLineDiffs();
|
||||||
$hunk_parser->generateVisibileLinesMask($lines_context);
|
$hunk_parser->generateVisibleLinesMask($lines_context);
|
||||||
|
|
||||||
$this->setOldLines($hunk_parser->getOldLines());
|
$this->setOldLines($hunk_parser->getOldLines());
|
||||||
$this->setNewLines($hunk_parser->getNewLines());
|
$this->setNewLines($hunk_parser->getNewLines());
|
||||||
$this->setIntraLineDiffs($hunk_parser->getIntraLineDiffs());
|
$this->setIntraLineDiffs($hunk_parser->getIntraLineDiffs());
|
||||||
$this->setDepthOnlyLines($hunk_parser->getDepthOnlyLines());
|
$this->setDepthOnlyLines($hunk_parser->getDepthOnlyLines());
|
||||||
$this->setVisibileLinesMask($hunk_parser->getVisibleLinesMask());
|
$this->setVisibleLinesMask($hunk_parser->getVisibleLinesMask());
|
||||||
$this->hunkStartLines = $hunk_parser->getHunkStartLines(
|
$this->hunkStartLines = $hunk_parser->getHunkStartLines(
|
||||||
$changeset->getHunks());
|
$changeset->getHunks());
|
||||||
|
|
||||||
@@ -868,8 +868,19 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
->setHighlightingDisabled($this->highlightingDisabled)
|
->setHighlightingDisabled($this->highlightingDisabled)
|
||||||
->setDepthOnlyLines($this->getDepthOnlyLines());
|
->setDepthOnlyLines($this->getDepthOnlyLines());
|
||||||
|
|
||||||
|
list($engine, $old_ref, $new_ref) = $this->newDocumentEngine();
|
||||||
|
if ($engine) {
|
||||||
|
$engine_blocks = $engine->newEngineBlocks(
|
||||||
|
$old_ref,
|
||||||
|
$new_ref);
|
||||||
|
} else {
|
||||||
|
$engine_blocks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$has_document_engine = ($engine_blocks !== null);
|
||||||
|
|
||||||
$shield = null;
|
$shield = null;
|
||||||
if ($this->isTopLevel && !$this->comments) {
|
if ($this->isTopLevel && !$this->comments && !$has_document_engine) {
|
||||||
if ($this->isGenerated()) {
|
if ($this->isGenerated()) {
|
||||||
$shield = $renderer->renderShield(
|
$shield = $renderer->renderShield(
|
||||||
pht(
|
pht(
|
||||||
@@ -1024,7 +1035,6 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
->setOldComments($old_comments)
|
->setOldComments($old_comments)
|
||||||
->setNewComments($new_comments);
|
->setNewComments($new_comments);
|
||||||
|
|
||||||
$engine_blocks = $this->newDocumentEngineChangesetView();
|
|
||||||
if ($engine_blocks !== null) {
|
if ($engine_blocks !== null) {
|
||||||
$reference = $this->getRenderingReference();
|
$reference = $this->getRenderingReference();
|
||||||
$parts = explode('/', $reference);
|
$parts = explode('/', $reference);
|
||||||
@@ -1041,6 +1051,10 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
$vs = $id;
|
$vs = $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$renderer
|
||||||
|
->setDocumentEngine($engine)
|
||||||
|
->setDocumentEngineBlocks($engine_blocks);
|
||||||
|
|
||||||
return $renderer->renderDocumentEngineBlocks(
|
return $renderer->renderDocumentEngineBlocks(
|
||||||
$engine_blocks,
|
$engine_blocks,
|
||||||
(string)$id,
|
(string)$id,
|
||||||
@@ -1653,7 +1667,7 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
return $prefix.$line;
|
return $prefix.$line;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newDocumentEngineChangesetView() {
|
private function newDocumentEngine() {
|
||||||
$changeset = $this->changeset;
|
$changeset = $this->changeset;
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
@@ -1724,7 +1738,8 @@ final class DifferentialChangesetParser extends Phobject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($document_engine) {
|
if ($document_engine) {
|
||||||
return $document_engine->newDiffView(
|
return array(
|
||||||
|
$document_engine,
|
||||||
$old_ref,
|
$old_ref,
|
||||||
$new_ref);
|
$new_ref);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ final class DifferentialHunkParser extends Phobject {
|
|||||||
}
|
}
|
||||||
public function getVisibleLinesMask() {
|
public function getVisibleLinesMask() {
|
||||||
if ($this->visibleLinesMask === null) {
|
if ($this->visibleLinesMask === null) {
|
||||||
throw new PhutilInvalidStateException('generateVisibileLinesMask');
|
throw new PhutilInvalidStateException('generateVisibleLinesMask');
|
||||||
}
|
}
|
||||||
return $this->visibleLinesMask;
|
return $this->visibleLinesMask;
|
||||||
}
|
}
|
||||||
@@ -354,7 +354,7 @@ final class DifferentialHunkParser extends Phobject {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateVisibileLinesMask($lines_context) {
|
public function generateVisibleLinesMask($lines_context) {
|
||||||
$old = $this->getOldLines();
|
$old = $this->getOldLines();
|
||||||
$new = $this->getNewLines();
|
$new = $this->getNewLines();
|
||||||
$max_length = max(count($old), count($new));
|
$max_length = max(count($old), count($new));
|
||||||
|
|||||||
@@ -270,11 +270,20 @@ abstract class DifferentialChangesetHTMLRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getHighlightingDisabled()) {
|
$blocks = $this->getDocumentEngineBlocks();
|
||||||
$messages[] = pht(
|
if ($blocks) {
|
||||||
'This file is larger than %s, so syntax highlighting is '.
|
foreach ($blocks->getMessages() as $message) {
|
||||||
'disabled by default.',
|
$messages[] = $message;
|
||||||
phutil_format_bytes(DifferentialChangesetParser::HIGHLIGHT_BYTE_LIMIT));
|
}
|
||||||
|
} else {
|
||||||
|
if ($this->getHighlightingDisabled()) {
|
||||||
|
$byte_limit = DifferentialChangesetParser::HIGHLIGHT_BYTE_LIMIT;
|
||||||
|
$byte_limit = phutil_format_bytes($byte_limit);
|
||||||
|
$messages[] = pht(
|
||||||
|
'This file is larger than %s, so syntax highlighting is '.
|
||||||
|
'disabled by default.',
|
||||||
|
$byte_limit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->formatHeaderMessages($messages);
|
return $this->formatHeaderMessages($messages);
|
||||||
|
|||||||
@@ -233,42 +233,233 @@ final class DifferentialChangesetOneUpRenderer
|
|||||||
$old_changeset_key,
|
$old_changeset_key,
|
||||||
$new_changeset_key) {
|
$new_changeset_key) {
|
||||||
|
|
||||||
// TODO: This should eventually merge into the normal primitives pathway,
|
$engine = $this->getDocumentEngine();
|
||||||
// but fake it for now and just share as much code as possible.
|
$layout = $block_list->newTwoUpLayout();
|
||||||
|
|
||||||
$primitives = array();
|
$old_comments = $this->getOldComments();
|
||||||
foreach ($block_list->newOneUpLayout() as $block) {
|
$new_comments = $this->getNewComments();
|
||||||
$primitives[] = array(
|
|
||||||
'type' => 'old-file',
|
$unchanged = array();
|
||||||
'htype' => '',
|
foreach ($layout as $key => $row) {
|
||||||
'line' => $block->getBlockKey(),
|
list($old, $new) = $row;
|
||||||
'render' => $block->newContentView(),
|
|
||||||
);
|
if (!$old) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$new) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old->getDifferenceType() !== null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new->getDifferenceType() !== null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$unchanged[$key] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We'd like to share primitive code here, but buildPrimitives()
|
$rows = array();
|
||||||
// currently chokes on changesets with no textual data.
|
$count = count($layout);
|
||||||
foreach ($this->getOldComments() as $line => $group) {
|
for ($ii = 0; $ii < $count;) {
|
||||||
foreach ($group as $comment) {
|
$start = $ii;
|
||||||
$primitives[] = array(
|
|
||||||
'type' => 'inline',
|
for ($jj = $ii; $jj < $count; $jj++) {
|
||||||
'comment' => $comment,
|
list($old, $new) = $layout[$jj];
|
||||||
'right' => false,
|
|
||||||
|
if (empty($unchanged[$jj])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
'type' => 'unchanged',
|
||||||
|
'layoutKey' => $jj,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
$ii = $jj;
|
||||||
|
|
||||||
|
for ($jj = $ii; $jj < $count; $jj++) {
|
||||||
|
list($old, $new) = $layout[$jj];
|
||||||
|
|
||||||
|
if (!empty($unchanged[$jj])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
'type' => 'old',
|
||||||
|
'layoutKey' => $jj,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($jj = $ii; $jj < $count; $jj++) {
|
||||||
|
list($old, $new) = $layout[$jj];
|
||||||
|
|
||||||
|
if (!empty($unchanged[$jj])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
'type' => 'new',
|
||||||
|
'layoutKey' => $jj,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$ii = $jj;
|
||||||
|
|
||||||
|
// We always expect to consume at least one row when iterating through
|
||||||
|
// the loop and make progress. If we don't, bail out to avoid spinning
|
||||||
|
// to death.
|
||||||
|
if ($ii === $start) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to make progress during 1up diff layout.'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->getNewComments() as $line => $group) {
|
$old_ref = null;
|
||||||
foreach ($group as $comment) {
|
$new_ref = null;
|
||||||
$primitives[] = array(
|
$refs = $block_list->getDocumentRefs();
|
||||||
'type' => 'inline',
|
if ($refs) {
|
||||||
'comment' => $comment,
|
list($old_ref, $new_ref) = $refs;
|
||||||
'right' => true,
|
}
|
||||||
);
|
|
||||||
|
$view = array();
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$row_type = $row['type'];
|
||||||
|
$layout_key = $row['layoutKey'];
|
||||||
|
$row_layout = $layout[$layout_key];
|
||||||
|
list($old, $new) = $row_layout;
|
||||||
|
|
||||||
|
if ($old) {
|
||||||
|
$old_key = $old->getBlockKey();
|
||||||
|
} else {
|
||||||
|
$old_key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new) {
|
||||||
|
$new_key = $new->getBlockKey();
|
||||||
|
} else {
|
||||||
|
$new_key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cells = array();
|
||||||
|
$cell_classes = array();
|
||||||
|
|
||||||
|
if ($row_type === 'unchanged') {
|
||||||
|
$cell_content = $engine->newBlockContentView(
|
||||||
|
$old_ref,
|
||||||
|
$old);
|
||||||
|
} else if ($old && $new) {
|
||||||
|
$block_diff = $engine->newBlockDiffViews(
|
||||||
|
$old_ref,
|
||||||
|
$old,
|
||||||
|
$new_ref,
|
||||||
|
$new);
|
||||||
|
|
||||||
|
// TODO: We're currently double-rendering this: once when building
|
||||||
|
// the old row, and once when building the new one. In both cases,
|
||||||
|
// we throw away the other half of the output. We could cache this
|
||||||
|
// to improve performance.
|
||||||
|
|
||||||
|
if ($row_type === 'old') {
|
||||||
|
$cell_content = $block_diff->getOldContent();
|
||||||
|
$cell_classes = $block_diff->getOldClasses();
|
||||||
|
} else {
|
||||||
|
$cell_content = $block_diff->getNewContent();
|
||||||
|
$cell_classes = $block_diff->getNewClasses();
|
||||||
|
}
|
||||||
|
} else if ($row_type === 'old') {
|
||||||
|
$cell_content = $engine->newBlockContentView(
|
||||||
|
$old_ref,
|
||||||
|
$old);
|
||||||
|
$cell_classes[] = 'old';
|
||||||
|
$cell_classes[] = 'old-full';
|
||||||
|
|
||||||
|
$new_key = null;
|
||||||
|
} else if ($row_type === 'new') {
|
||||||
|
$cell_content = $engine->newBlockContentView(
|
||||||
|
$new_ref,
|
||||||
|
$new);
|
||||||
|
$cell_classes[] = 'new';
|
||||||
|
$cell_classes[] = 'new-full';
|
||||||
|
|
||||||
|
$old_key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old_key === null) {
|
||||||
|
$old_id = null;
|
||||||
|
} else {
|
||||||
|
$old_id = "C{$old_changeset_key}OL{$old_key}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new_key === null) {
|
||||||
|
$new_id = null;
|
||||||
|
} else {
|
||||||
|
$new_id = "C{$new_changeset_key}NL{$new_key}";
|
||||||
|
}
|
||||||
|
|
||||||
|
$cells[] = phutil_tag(
|
||||||
|
'td',
|
||||||
|
array(
|
||||||
|
'id' => $old_id,
|
||||||
|
'data-n' => $old_key,
|
||||||
|
'class' => 'n',
|
||||||
|
));
|
||||||
|
|
||||||
|
$cells[] = phutil_tag(
|
||||||
|
'td',
|
||||||
|
array(
|
||||||
|
'id' => $new_id,
|
||||||
|
'data-n' => $new_key,
|
||||||
|
'class' => 'n',
|
||||||
|
));
|
||||||
|
|
||||||
|
$cells[] = phutil_tag(
|
||||||
|
'td',
|
||||||
|
array(
|
||||||
|
'class' => 'copy',
|
||||||
|
));
|
||||||
|
|
||||||
|
$cell_classes[] = 'diff-flush';
|
||||||
|
$cell_classes = implode(' ', $cell_classes);
|
||||||
|
|
||||||
|
$cells[] = phutil_tag(
|
||||||
|
'td',
|
||||||
|
array(
|
||||||
|
'class' => $cell_classes,
|
||||||
|
'data-copy-mode' => 'copy-unified',
|
||||||
|
),
|
||||||
|
$cell_content);
|
||||||
|
|
||||||
|
$view[] = phutil_tag(
|
||||||
|
'tr',
|
||||||
|
array(),
|
||||||
|
$cells);
|
||||||
|
|
||||||
|
if ($old_key !== null) {
|
||||||
|
$old_inlines = idx($old_comments, $old_key, array());
|
||||||
|
foreach ($old_inlines as $inline) {
|
||||||
|
$inline = $this->buildInlineComment(
|
||||||
|
$inline,
|
||||||
|
$on_right = false);
|
||||||
|
$view[] = $this->getRowScaffoldForInline($inline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new_key !== null) {
|
||||||
|
$new_inlines = idx($new_comments, $new_key, array());
|
||||||
|
foreach ($new_inlines as $inline) {
|
||||||
|
$inline = $this->buildInlineComment(
|
||||||
|
$inline,
|
||||||
|
$on_right = true);
|
||||||
|
$view[] = $this->getRowScaffoldForInline($inline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$output = $this->renderPrimitives($primitives, 1);
|
$output = $this->wrapChangeInTable($view);
|
||||||
return $this->renderChangesetTable($output);
|
return $this->renderChangesetTable($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ abstract class DifferentialChangesetRenderer extends Phobject {
|
|||||||
private $scopeEngine = false;
|
private $scopeEngine = false;
|
||||||
private $depthOnlyLines;
|
private $depthOnlyLines;
|
||||||
|
|
||||||
|
private $documentEngine;
|
||||||
|
private $documentEngineBlocks;
|
||||||
|
|
||||||
private $oldFile = false;
|
private $oldFile = false;
|
||||||
private $newFile = false;
|
private $newFile = false;
|
||||||
|
|
||||||
@@ -239,6 +242,25 @@ abstract class DifferentialChangesetRenderer extends Phobject {
|
|||||||
return $this->oldChangesetID;
|
return $this->oldChangesetID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setDocumentEngine(PhabricatorDocumentEngine $engine) {
|
||||||
|
$this->documentEngine = $engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDocumentEngine() {
|
||||||
|
return $this->documentEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDocumentEngineBlocks(
|
||||||
|
PhabricatorDocumentEngineBlocks $blocks) {
|
||||||
|
$this->documentEngineBlocks = $blocks;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDocumentEngineBlocks() {
|
||||||
|
return $this->documentEngineBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
public function setNewComments(array $new_comments) {
|
public function setNewComments(array $new_comments) {
|
||||||
foreach ($new_comments as $line_number => $comments) {
|
foreach ($new_comments as $line_number => $comments) {
|
||||||
assert_instances_of($comments, 'PhabricatorInlineCommentInterface');
|
assert_instances_of($comments, 'PhabricatorInlineCommentInterface');
|
||||||
@@ -355,6 +377,16 @@ abstract class DifferentialChangesetRenderer extends Phobject {
|
|||||||
$notice = null;
|
$notice = null;
|
||||||
if ($this->getIsTopLevel()) {
|
if ($this->getIsTopLevel()) {
|
||||||
$force = (!$content && !$props);
|
$force = (!$content && !$props);
|
||||||
|
|
||||||
|
// If we have DocumentEngine messages about the blocks, assume they
|
||||||
|
// explain why there's no content.
|
||||||
|
$blocks = $this->getDocumentEngineBlocks();
|
||||||
|
if ($blocks) {
|
||||||
|
if ($blocks->getMessages()) {
|
||||||
|
$force = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$notice = $this->renderChangeTypeHeader($force);
|
$notice = $this->renderChangeTypeHeader($force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -369,52 +369,123 @@ final class DifferentialChangesetTwoUpRenderer
|
|||||||
$old_changeset_key,
|
$old_changeset_key,
|
||||||
$new_changeset_key) {
|
$new_changeset_key) {
|
||||||
|
|
||||||
|
$engine = $this->getDocumentEngine();
|
||||||
|
|
||||||
|
$old_ref = null;
|
||||||
|
$new_ref = null;
|
||||||
|
$refs = $block_list->getDocumentRefs();
|
||||||
|
if ($refs) {
|
||||||
|
list($old_ref, $new_ref) = $refs;
|
||||||
|
}
|
||||||
|
|
||||||
$old_comments = $this->getOldComments();
|
$old_comments = $this->getOldComments();
|
||||||
$new_comments = $this->getNewComments();
|
$new_comments = $this->getNewComments();
|
||||||
|
|
||||||
|
$gap_view = javelin_tag(
|
||||||
|
'tr',
|
||||||
|
array(
|
||||||
|
'sigil' => 'context-target',
|
||||||
|
),
|
||||||
|
phutil_tag(
|
||||||
|
'td',
|
||||||
|
array(
|
||||||
|
'colspan' => 6,
|
||||||
|
'class' => 'show-more',
|
||||||
|
),
|
||||||
|
pht("\xE2\x80\xA2 \xE2\x80\xA2 \xE2\x80\xA2")));
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
|
$in_gap = false;
|
||||||
foreach ($block_list->newTwoUpLayout() as $row) {
|
foreach ($block_list->newTwoUpLayout() as $row) {
|
||||||
list($old, $new) = $row;
|
list($old, $new) = $row;
|
||||||
|
|
||||||
if ($old) {
|
if ($old) {
|
||||||
$old_content = $old->newContentView();
|
|
||||||
$old_key = $old->getBlockKey();
|
$old_key = $old->getBlockKey();
|
||||||
|
$is_visible = $old->getIsVisible();
|
||||||
$old_classes = $old->getClasses();
|
|
||||||
|
|
||||||
if ($old->getDifferenceType() === '-') {
|
|
||||||
$old_classes[] = 'old';
|
|
||||||
$old_classes[] = 'old-full';
|
|
||||||
}
|
|
||||||
|
|
||||||
$old_classes[] = 'diff-flush';
|
|
||||||
|
|
||||||
$old_classes = implode(' ', $old_classes);
|
|
||||||
} else {
|
} else {
|
||||||
$old_content = null;
|
|
||||||
$old_key = null;
|
$old_key = null;
|
||||||
$old_classes = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($new) {
|
if ($new) {
|
||||||
$new_content = $new->newContentView();
|
|
||||||
$new_key = $new->getBlockKey();
|
$new_key = $new->getBlockKey();
|
||||||
$new_classes = $new->getClasses();
|
$is_visible = $new->getIsVisible();
|
||||||
|
} else {
|
||||||
|
$new_key = null;
|
||||||
|
}
|
||||||
|
|
||||||
if ($new->getDifferenceType() === '+') {
|
if (!$is_visible) {
|
||||||
$new_classes[] = 'new';
|
if (!$in_gap) {
|
||||||
$new_classes[] = 'new-full';
|
$in_gap = true;
|
||||||
|
$rows[] = $gap_view;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($in_gap) {
|
||||||
|
$in_gap = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old) {
|
||||||
|
$is_rem = ($old->getDifferenceType() === '-');
|
||||||
|
} else {
|
||||||
|
$is_rem = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($new) {
|
||||||
|
$is_add = ($new->getDifferenceType() === '+');
|
||||||
|
} else {
|
||||||
|
$is_add = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_rem && $is_add) {
|
||||||
|
$block_diff = $engine->newBlockDiffViews(
|
||||||
|
$old_ref,
|
||||||
|
$old,
|
||||||
|
$new_ref,
|
||||||
|
$new);
|
||||||
|
|
||||||
|
$old_content = $block_diff->getOldContent();
|
||||||
|
$new_content = $block_diff->getNewContent();
|
||||||
|
|
||||||
|
$old_classes = $block_diff->getOldClasses();
|
||||||
|
$new_classes = $block_diff->getNewClasses();
|
||||||
|
} else {
|
||||||
|
$old_classes = array();
|
||||||
|
$new_classes = array();
|
||||||
|
|
||||||
|
if ($old) {
|
||||||
|
$old_content = $engine->newBlockContentView(
|
||||||
|
$old_ref,
|
||||||
|
$old);
|
||||||
|
|
||||||
|
if ($is_rem) {
|
||||||
|
$old_classes[] = 'old';
|
||||||
|
$old_classes[] = 'old-full';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$old_content = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_classes[] = 'diff-flush';
|
if ($new) {
|
||||||
|
$new_content = $engine->newBlockContentView(
|
||||||
|
$new_ref,
|
||||||
|
$new);
|
||||||
|
|
||||||
$new_classes = implode(' ', $new_classes);
|
if ($is_add) {
|
||||||
} else {
|
$new_classes[] = 'new';
|
||||||
$new_content = null;
|
$new_classes[] = 'new-full';
|
||||||
$new_key = null;
|
}
|
||||||
$new_classes = null;
|
} else {
|
||||||
|
$new_content = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$old_classes[] = 'diff-flush';
|
||||||
|
$old_classes = implode(' ', $old_classes);
|
||||||
|
|
||||||
|
$new_classes[] = 'diff-flush';
|
||||||
|
$new_classes = implode(' ', $new_classes);
|
||||||
|
|
||||||
$old_inline_rows = array();
|
$old_inline_rows = array();
|
||||||
if ($old_key !== null) {
|
if ($old_key !== null) {
|
||||||
$old_inlines = idx($old_comments, $old_key, array());
|
$old_inlines = idx($old_comments, $old_key, array());
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ final class PhabricatorDocumentEngineBlock
|
|||||||
|
|
||||||
private $blockKey;
|
private $blockKey;
|
||||||
private $content;
|
private $content;
|
||||||
private $classes = array();
|
|
||||||
private $differenceHash;
|
private $differenceHash;
|
||||||
private $differenceType;
|
private $differenceType;
|
||||||
|
private $isVisible;
|
||||||
|
|
||||||
public function setContent($content) {
|
public function setContent($content) {
|
||||||
$this->content = $content;
|
$this->content = $content;
|
||||||
@@ -18,10 +18,6 @@ final class PhabricatorDocumentEngineBlock
|
|||||||
return $this->content;
|
return $this->content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newContentView() {
|
|
||||||
return $this->getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBlockKey($block_key) {
|
public function setBlockKey($block_key) {
|
||||||
$this->blockKey = $block_key;
|
$this->blockKey = $block_key;
|
||||||
return $this;
|
return $this;
|
||||||
@@ -31,15 +27,6 @@ final class PhabricatorDocumentEngineBlock
|
|||||||
return $this->blockKey;
|
return $this->blockKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addClass($class) {
|
|
||||||
$this->classes[] = $class;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getClasses() {
|
|
||||||
return $this->classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDifferenceHash($difference_hash) {
|
public function setDifferenceHash($difference_hash) {
|
||||||
$this->differenceHash = $difference_hash;
|
$this->differenceHash = $difference_hash;
|
||||||
return $this;
|
return $this;
|
||||||
@@ -58,4 +45,13 @@ final class PhabricatorDocumentEngineBlock
|
|||||||
return $this->differenceType;
|
return $this->differenceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIsVisible($is_visible) {
|
||||||
|
$this->isVisible = $is_visible;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsVisible() {
|
||||||
|
return $this->isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorDocumentEngineBlockDiff
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $oldContent;
|
||||||
|
private $newContent;
|
||||||
|
private $oldClasses = array();
|
||||||
|
private $newClasses = array();
|
||||||
|
|
||||||
|
public function setOldContent($old_content) {
|
||||||
|
$this->oldContent = $old_content;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOldContent() {
|
||||||
|
return $this->oldContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNewContent($new_content) {
|
||||||
|
$this->newContent = $new_content;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewContent() {
|
||||||
|
return $this->newContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addOldClass($class) {
|
||||||
|
$this->oldClasses[] = $class;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOldClasses() {
|
||||||
|
return $this->oldClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addNewClass($class) {
|
||||||
|
$this->newClasses[] = $class;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewClasses() {
|
||||||
|
return $this->newClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,6 +4,16 @@ final class PhabricatorDocumentEngineBlocks
|
|||||||
extends Phobject {
|
extends Phobject {
|
||||||
|
|
||||||
private $lists = array();
|
private $lists = array();
|
||||||
|
private $messages = array();
|
||||||
|
|
||||||
|
public function addMessage($message) {
|
||||||
|
$this->messages[] = $message;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMessages() {
|
||||||
|
return $this->messages;
|
||||||
|
}
|
||||||
|
|
||||||
public function addBlockList(PhabricatorDocumentRef $ref, array $blocks) {
|
public function addBlockList(PhabricatorDocumentRef $ref, array $blocks) {
|
||||||
assert_instances_of($blocks, 'PhabricatorDocumentEngineBlock');
|
assert_instances_of($blocks, 'PhabricatorDocumentEngineBlock');
|
||||||
@@ -16,10 +26,18 @@ final class PhabricatorDocumentEngineBlocks
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDocumentRefs() {
|
||||||
|
return ipull($this->lists, 'ref');
|
||||||
|
}
|
||||||
|
|
||||||
public function newTwoUpLayout() {
|
public function newTwoUpLayout() {
|
||||||
$rows = array();
|
$rows = array();
|
||||||
$lists = $this->lists;
|
$lists = $this->lists;
|
||||||
|
|
||||||
|
if (count($lists) != 2) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
$specs = array();
|
$specs = array();
|
||||||
foreach ($this->lists as $list) {
|
foreach ($this->lists as $list) {
|
||||||
$specs[] = $this->newDiffSpec($list['blocks']);
|
$specs[] = $this->newDiffSpec($list['blocks']);
|
||||||
@@ -38,6 +56,9 @@ final class PhabricatorDocumentEngineBlocks
|
|||||||
->parseHunksForLineData($changeset->getHunks())
|
->parseHunksForLineData($changeset->getHunks())
|
||||||
->reparseHunksForSpecialAttributes();
|
->reparseHunksForSpecialAttributes();
|
||||||
|
|
||||||
|
$hunk_parser->generateVisibleLinesMask(2);
|
||||||
|
$mask = $hunk_parser->getVisibleLinesMask();
|
||||||
|
|
||||||
$old_lines = $hunk_parser->getOldLines();
|
$old_lines = $hunk_parser->getOldLines();
|
||||||
$new_lines = $hunk_parser->getNewLines();
|
$new_lines = $hunk_parser->getNewLines();
|
||||||
|
|
||||||
@@ -48,6 +69,15 @@ final class PhabricatorDocumentEngineBlocks
|
|||||||
$old_line = idx($old_lines, $ii);
|
$old_line = idx($old_lines, $ii);
|
||||||
$new_line = idx($new_lines, $ii);
|
$new_line = idx($new_lines, $ii);
|
||||||
|
|
||||||
|
$is_visible = !empty($mask[$ii + 1]);
|
||||||
|
|
||||||
|
// TODO: There's currently a bug where one-line files get incorrectly
|
||||||
|
// masked. This causes images to completely fail to render. Just ignore
|
||||||
|
// the mask if it came back empty.
|
||||||
|
if (!$mask) {
|
||||||
|
$is_visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
if ($old_line) {
|
if ($old_line) {
|
||||||
$old_hash = rtrim($old_line['text'], "\n");
|
$old_hash = rtrim($old_line['text'], "\n");
|
||||||
if (!strlen($old_hash)) {
|
if (!strlen($old_hash)) {
|
||||||
@@ -55,7 +85,9 @@ final class PhabricatorDocumentEngineBlocks
|
|||||||
$old_block = null;
|
$old_block = null;
|
||||||
} else {
|
} else {
|
||||||
$old_block = array_shift($old_map[$old_hash]);
|
$old_block = array_shift($old_map[$old_hash]);
|
||||||
$old_block->setDifferenceType($old_line['type']);
|
$old_block
|
||||||
|
->setDifferenceType($old_line['type'])
|
||||||
|
->setIsVisible($is_visible);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$old_block = null;
|
$old_block = null;
|
||||||
@@ -67,7 +99,9 @@ final class PhabricatorDocumentEngineBlocks
|
|||||||
$new_block = null;
|
$new_block = null;
|
||||||
} else {
|
} else {
|
||||||
$new_block = array_shift($new_map[$new_hash]);
|
$new_block = array_shift($new_map[$new_hash]);
|
||||||
$new_block->setDifferenceType($new_line['type']);
|
$new_block
|
||||||
|
->setDifferenceType($new_line['type'])
|
||||||
|
->setIsVisible($is_visible);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$new_block = null;
|
$new_block = null;
|
||||||
|
|||||||
@@ -37,7 +37,31 @@ abstract class PhabricatorDocumentEngine
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newDiffView(
|
public function newBlockDiffViews(
|
||||||
|
PhabricatorDocumentRef $uref,
|
||||||
|
PhabricatorDocumentEngineBlock $ublock,
|
||||||
|
PhabricatorDocumentRef $vref,
|
||||||
|
PhabricatorDocumentEngineBlock $vblock) {
|
||||||
|
|
||||||
|
$u_content = $this->newBlockContentView($uref, $ublock);
|
||||||
|
$v_content = $this->newBlockContentView($vref, $vblock);
|
||||||
|
|
||||||
|
return id(new PhabricatorDocumentEngineBlockDiff())
|
||||||
|
->setOldContent($u_content)
|
||||||
|
->addOldClass('old')
|
||||||
|
->addOldClass('old-full')
|
||||||
|
->setNewContent($v_content)
|
||||||
|
->addNewClass('new')
|
||||||
|
->addNewClass('new-full');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newBlockContentView(
|
||||||
|
PhabricatorDocumentRef $ref,
|
||||||
|
PhabricatorDocumentEngineBlock $block) {
|
||||||
|
return $block->getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newEngineBlocks(
|
||||||
PhabricatorDocumentRef $uref,
|
PhabricatorDocumentRef $uref,
|
||||||
PhabricatorDocumentRef $vref) {
|
PhabricatorDocumentRef $vref) {
|
||||||
throw new PhutilMethodNotImplementedException();
|
throw new PhutilMethodNotImplementedException();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ final class PhabricatorImageDocumentEngine
|
|||||||
return ($uref->getFile() && $vref->getFile());
|
return ($uref->getFile() && $vref->getFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newDiffView(
|
public function newEngineBlocks(
|
||||||
PhabricatorDocumentRef $uref,
|
PhabricatorDocumentRef $uref,
|
||||||
PhabricatorDocumentRef $vref) {
|
PhabricatorDocumentRef $vref) {
|
||||||
|
|
||||||
@@ -39,6 +39,23 @@ final class PhabricatorImageDocumentEngine
|
|||||||
->addBlockList($vref, $v_blocks);
|
->addBlockList($vref, $v_blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newBlockDiffViews(
|
||||||
|
PhabricatorDocumentRef $uref,
|
||||||
|
PhabricatorDocumentEngineBlock $ublock,
|
||||||
|
PhabricatorDocumentRef $vref,
|
||||||
|
PhabricatorDocumentEngineBlock $vblock) {
|
||||||
|
|
||||||
|
$u_content = $this->newBlockContentView($uref, $ublock);
|
||||||
|
$v_content = $this->newBlockContentView($vref, $vblock);
|
||||||
|
|
||||||
|
return id(new PhabricatorDocumentEngineBlockDiff())
|
||||||
|
->setOldContent($u_content)
|
||||||
|
->addOldClass('diff-image-cell')
|
||||||
|
->setNewContent($v_content)
|
||||||
|
->addNewClass('diff-image-cell');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function newDiffBlocks(PhabricatorDocumentRef $ref) {
|
private function newDiffBlocks(PhabricatorDocumentRef $ref) {
|
||||||
$blocks = array();
|
$blocks = array();
|
||||||
|
|
||||||
@@ -59,7 +76,6 @@ final class PhabricatorImageDocumentEngine
|
|||||||
|
|
||||||
$blocks[] = id(new PhabricatorDocumentEngineBlock())
|
$blocks[] = id(new PhabricatorDocumentEngineBlock())
|
||||||
->setBlockKey('1')
|
->setBlockKey('1')
|
||||||
->addClass('diff-image-cell')
|
|
||||||
->setDifferenceHash($hash)
|
->setDifferenceHash($hash)
|
||||||
->setContent($image_view);
|
->setContent($image_view);
|
||||||
|
|
||||||
|
|||||||
@@ -41,16 +41,143 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newDiffView(
|
public function newEngineBlocks(
|
||||||
PhabricatorDocumentRef $uref,
|
PhabricatorDocumentRef $uref,
|
||||||
PhabricatorDocumentRef $vref) {
|
PhabricatorDocumentRef $vref) {
|
||||||
|
|
||||||
$u_blocks = $this->newDiffBlocks($uref);
|
$blocks = new PhabricatorDocumentEngineBlocks();
|
||||||
$v_blocks = $this->newDiffBlocks($vref);
|
|
||||||
|
|
||||||
return id(new PhabricatorDocumentEngineBlocks())
|
try {
|
||||||
->addBlockList($uref, $u_blocks)
|
$u_blocks = $this->newDiffBlocks($uref);
|
||||||
->addBlockList($vref, $v_blocks);
|
$v_blocks = $this->newDiffBlocks($vref);
|
||||||
|
|
||||||
|
$blocks->addBlockList($uref, $u_blocks);
|
||||||
|
$blocks->addBlockList($vref, $v_blocks);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$blocks->addMessage($ex->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newBlockDiffViews(
|
||||||
|
PhabricatorDocumentRef $uref,
|
||||||
|
PhabricatorDocumentEngineBlock $ublock,
|
||||||
|
PhabricatorDocumentRef $vref,
|
||||||
|
PhabricatorDocumentEngineBlock $vblock) {
|
||||||
|
|
||||||
|
$ucell = $ublock->getContent();
|
||||||
|
$vcell = $vblock->getContent();
|
||||||
|
|
||||||
|
$utype = idx($ucell, 'cell_type');
|
||||||
|
$vtype = idx($vcell, 'cell_type');
|
||||||
|
|
||||||
|
if ($utype === $vtype) {
|
||||||
|
switch ($utype) {
|
||||||
|
case 'markdown':
|
||||||
|
$usource = idx($ucell, 'source');
|
||||||
|
$usource = implode('', $usource);
|
||||||
|
|
||||||
|
$vsource = idx($vcell, 'source');
|
||||||
|
$vsource = implode('', $vsource);
|
||||||
|
|
||||||
|
$diff = id(new PhutilProseDifferenceEngine())
|
||||||
|
->getDiff($usource, $vsource);
|
||||||
|
|
||||||
|
$u_content = $this->newProseDiffCell($diff, array('=', '-'));
|
||||||
|
$v_content = $this->newProseDiffCell($diff, array('=', '+'));
|
||||||
|
|
||||||
|
$u_content = $this->newJupyterCell(null, $u_content, null);
|
||||||
|
$v_content = $this->newJupyterCell(null, $v_content, null);
|
||||||
|
|
||||||
|
$u_content = $this->newCellContainer($u_content);
|
||||||
|
$v_content = $this->newCellContainer($v_content);
|
||||||
|
|
||||||
|
return id(new PhabricatorDocumentEngineBlockDiff())
|
||||||
|
->setOldContent($u_content)
|
||||||
|
->addOldClass('old')
|
||||||
|
->setNewContent($v_content)
|
||||||
|
->addNewClass('new');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::newBlockDiffViews($uref, $ublock, $vref, $vblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newBlockContentView(
|
||||||
|
PhabricatorDocumentRef $ref,
|
||||||
|
PhabricatorDocumentEngineBlock $block) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$cell = $block->getContent();
|
||||||
|
|
||||||
|
$cell_content = $this->renderJupyterCell($viewer, $cell);
|
||||||
|
|
||||||
|
return $this->newCellContainer($cell_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newCellContainer($cell_content) {
|
||||||
|
$notebook_table = phutil_tag(
|
||||||
|
'table',
|
||||||
|
array(
|
||||||
|
'class' => 'jupyter-notebook',
|
||||||
|
),
|
||||||
|
$cell_content);
|
||||||
|
|
||||||
|
$container = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'document-engine-jupyter document-engine-diff',
|
||||||
|
),
|
||||||
|
$notebook_table);
|
||||||
|
|
||||||
|
return $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newProseDiffCell(PhutilProseDiff $diff, array $mask) {
|
||||||
|
$mask = array_fuse($mask);
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach ($diff->getParts() as $part) {
|
||||||
|
$type = $part['type'];
|
||||||
|
$text = $part['text'];
|
||||||
|
|
||||||
|
if (!isset($mask[$type])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case '-':
|
||||||
|
$result[] = phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => 'bright',
|
||||||
|
),
|
||||||
|
$text);
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
$result[] = phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => 'bright',
|
||||||
|
),
|
||||||
|
$text);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
$result[] = $text;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
null,
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'jupyter-cell-markdown',
|
||||||
|
),
|
||||||
|
$result),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newDiffBlocks(PhabricatorDocumentRef $ref) {
|
private function newDiffBlocks(PhabricatorDocumentRef $ref) {
|
||||||
@@ -62,22 +189,6 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
$idx = 1;
|
$idx = 1;
|
||||||
$blocks = array();
|
$blocks = array();
|
||||||
foreach ($cells as $cell) {
|
foreach ($cells as $cell) {
|
||||||
$cell_content = $this->renderJupyterCell($viewer, $cell);
|
|
||||||
|
|
||||||
$notebook_table = phutil_tag(
|
|
||||||
'table',
|
|
||||||
array(
|
|
||||||
'class' => 'jupyter-notebook',
|
|
||||||
),
|
|
||||||
$cell_content);
|
|
||||||
|
|
||||||
$container = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'document-engine-jupyter document-engine-diff',
|
|
||||||
),
|
|
||||||
$notebook_table);
|
|
||||||
|
|
||||||
// When the cell is a source code line, we can hash just the raw
|
// When the cell is a source code line, we can hash just the raw
|
||||||
// input rather than all the cell metadata.
|
// input rather than all the cell metadata.
|
||||||
|
|
||||||
@@ -85,6 +196,9 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
case 'code/line':
|
case 'code/line':
|
||||||
$hash_input = $cell['raw'];
|
$hash_input = $cell['raw'];
|
||||||
break;
|
break;
|
||||||
|
case 'markdown':
|
||||||
|
$hash_input = implode('', $cell['source']);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$hash_input = serialize($cell);
|
$hash_input = serialize($cell);
|
||||||
break;
|
break;
|
||||||
@@ -97,7 +211,7 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
$blocks[] = id(new PhabricatorDocumentEngineBlock())
|
$blocks[] = id(new PhabricatorDocumentEngineBlock())
|
||||||
->setBlockKey($idx)
|
->setBlockKey($idx)
|
||||||
->setDifferenceHash($hash)
|
->setDifferenceHash($hash)
|
||||||
->setContent($container);
|
->setContent($cell);
|
||||||
|
|
||||||
$idx++;
|
$idx++;
|
||||||
}
|
}
|
||||||
@@ -197,6 +311,26 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
foreach ($cells as $cell) {
|
foreach ($cells as $cell) {
|
||||||
$cell_type = idx($cell, 'cell_type');
|
$cell_type = idx($cell, 'cell_type');
|
||||||
|
|
||||||
|
if ($cell_type === 'markdown') {
|
||||||
|
$source = $cell['source'];
|
||||||
|
$source = implode('', $source);
|
||||||
|
|
||||||
|
// Attempt to split contiguous blocks of markdown into smaller
|
||||||
|
// pieces.
|
||||||
|
|
||||||
|
$chunks = preg_split(
|
||||||
|
'/\n\n+/',
|
||||||
|
$source);
|
||||||
|
|
||||||
|
foreach ($chunks as $chunk) {
|
||||||
|
$result = $cell;
|
||||||
|
$result['source'] = array($chunk);
|
||||||
|
$results[] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($cell_type !== 'code') {
|
if ($cell_type !== 'code') {
|
||||||
$results[] = $cell;
|
$results[] = $cell;
|
||||||
continue;
|
continue;
|
||||||
@@ -254,13 +388,6 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
|
|
||||||
list($label, $content) = $this->renderJupyterCellContent($viewer, $cell);
|
list($label, $content) = $this->renderJupyterCellContent($viewer, $cell);
|
||||||
|
|
||||||
$label_cell = phutil_tag(
|
|
||||||
'td',
|
|
||||||
array(
|
|
||||||
'class' => 'jupyter-label',
|
|
||||||
),
|
|
||||||
$label);
|
|
||||||
|
|
||||||
$classes = null;
|
$classes = null;
|
||||||
switch (idx($cell, 'cell_type')) {
|
switch (idx($cell, 'cell_type')) {
|
||||||
case 'code/line':
|
case 'code/line':
|
||||||
@@ -268,6 +395,20 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->newJupyterCell(
|
||||||
|
$label,
|
||||||
|
$content,
|
||||||
|
$classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newJupyterCell($label, $content, $classes) {
|
||||||
|
$label_cell = phutil_tag(
|
||||||
|
'td',
|
||||||
|
array(
|
||||||
|
'class' => 'jupyter-label',
|
||||||
|
),
|
||||||
|
$label);
|
||||||
|
|
||||||
$content_cell = phutil_tag(
|
$content_cell = phutil_tag(
|
||||||
'td',
|
'td',
|
||||||
array(
|
array(
|
||||||
@@ -300,7 +441,8 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
return $this->newCodeOutputCell($cell);
|
return $this->newCodeOutputCell($cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->newRawCell(id(new PhutilJSON())->encodeFormatted($cell));
|
return $this->newRawCell(id(new PhutilJSON())
|
||||||
|
->encodeFormatted($cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newRawCell($content) {
|
private function newRawCell($content) {
|
||||||
@@ -321,8 +463,9 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
$content = array();
|
$content = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = implode('', $content);
|
// TODO: This should ideally highlight as Markdown, but the "md"
|
||||||
$content = phutil_escape_html_newlines($content);
|
// highlighter in Pygments is painfully slow and not terribly useful.
|
||||||
|
$content = $this->highlightLines($content, 'txt');
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
null,
|
null,
|
||||||
@@ -507,15 +650,20 @@ final class PhabricatorJupyterDocumentEngine
|
|||||||
return $label;
|
return $label;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function highlightLines(array $lines) {
|
private function highlightLines(array $lines, $force_language = null) {
|
||||||
$head = head($lines);
|
if ($force_language === null) {
|
||||||
$matches = null;
|
$head = head($lines);
|
||||||
if (preg_match('/^%%(.*)$/', $head, $matches)) {
|
$matches = null;
|
||||||
$restore = array_shift($lines);
|
if (preg_match('/^%%(.*)$/', $head, $matches)) {
|
||||||
$lang = $matches[1];
|
$restore = array_shift($lines);
|
||||||
|
$lang = $matches[1];
|
||||||
|
} else {
|
||||||
|
$restore = null;
|
||||||
|
$lang = 'py';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$restore = null;
|
$restore = null;
|
||||||
$lang = 'py';
|
$lang = $force_language;
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = PhabricatorSyntaxHighlighter::highlightWithLanguage(
|
$content = PhabricatorSyntaxHighlighter::highlightWithLanguage(
|
||||||
|
|||||||
@@ -378,15 +378,15 @@ final class PhabricatorPasteQuery
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function highlightSource($source, $title, $language) {
|
private function highlightSource($source, $title, $language) {
|
||||||
if (empty($language)) {
|
if (empty($language)) {
|
||||||
return PhabricatorSyntaxHighlighter::highlightWithFilename(
|
return PhabricatorSyntaxHighlighter::highlightWithFilename(
|
||||||
$title,
|
$title,
|
||||||
$source);
|
$source);
|
||||||
} else {
|
} else {
|
||||||
return PhabricatorSyntaxHighlighter::highlightWithLanguage(
|
return PhabricatorSyntaxHighlighter::highlightWithLanguage(
|
||||||
$language,
|
$language,
|
||||||
$source);
|
$source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ final class PHUIDiffOneUpInlineCommentRowScaffold
|
|||||||
$inline = head($inlines);
|
$inline = head($inlines);
|
||||||
|
|
||||||
$attrs = array(
|
$attrs = array(
|
||||||
'colspan' => 3,
|
'colspan' => 2,
|
||||||
'id' => $inline->getScaffoldCellID(),
|
'id' => $inline->getScaffoldCellID(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@ final class PHUIDiffOneUpInlineCommentRowScaffold
|
|||||||
$cells = array(
|
$cells = array(
|
||||||
phutil_tag('td', array('class' => 'n'), $left_hidden),
|
phutil_tag('td', array('class' => 'n'), $left_hidden),
|
||||||
phutil_tag('td', array('class' => 'n'), $right_hidden),
|
phutil_tag('td', array('class' => 'n'), $right_hidden),
|
||||||
|
phutil_tag('td', array('class' => 'copy')),
|
||||||
phutil_tag('td', $attrs, $inline),
|
phutil_tag('td', $attrs, $inline),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -315,6 +315,16 @@ div.phui-property-list-stacked .phui-property-list-properties
|
|||||||
border-width: 0 1px;
|
border-width: 0 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.new .jupyter-cell-code-line {
|
||||||
|
background: {$new-background};
|
||||||
|
border-color: {$new-bright};
|
||||||
|
}
|
||||||
|
|
||||||
|
td.old .jupyter-cell-code-line {
|
||||||
|
background: {$old-background};
|
||||||
|
border-color: {$old-bright};
|
||||||
|
}
|
||||||
|
|
||||||
.jupyter-cell-code-head {
|
.jupyter-cell-code-head {
|
||||||
border-top-width: 1px;
|
border-top-width: 1px;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
@@ -364,3 +374,7 @@ div.phui-property-list-stacked .phui-property-list-properties
|
|||||||
.jupyter-output-html {
|
.jupyter-output-html {
|
||||||
background: {$sh-indigobackground};
|
background: {$sh-indigobackground};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jupyter-cell-markdown {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user