Path: blob/master/src/applications/files/diff/PhabricatorDocumentEngineBlocks.php
12242 views
<?php12final class PhabricatorDocumentEngineBlocks3extends Phobject {45private $lists = array();6private $messages = array();7private $rangeMin;8private $rangeMax;9private $revealedIndexes;10private $layoutAvailableRowCount;1112public function setRange($min, $max) {13$this->rangeMin = $min;14$this->rangeMax = $max;15return $this;16}1718public function setRevealedIndexes(array $indexes) {19$this->revealedIndexes = $indexes;20return $this;21}2223public function getLayoutAvailableRowCount() {24if ($this->layoutAvailableRowCount === null) {25throw new PhutilInvalidStateException('new...Layout');26}2728return $this->layoutAvailableRowCount;29}3031public function addMessage($message) {32$this->messages[] = $message;33return $this;34}3536public function getMessages() {37return $this->messages;38}3940public function addBlockList(41PhabricatorDocumentRef $ref = null,42array $blocks = array()) {4344assert_instances_of($blocks, 'PhabricatorDocumentEngineBlock');4546$this->lists[] = array(47'ref' => $ref,48'blocks' => array_values($blocks),49);5051return $this;52}5354public function getDocumentRefs() {55return ipull($this->lists, 'ref');56}5758public function newTwoUpLayout() {59$rows = array();60$lists = $this->lists;6162if (count($lists) != 2) {63$this->layoutAvailableRowCount = 0;64return array();65}6667$specs = array();68foreach ($this->lists as $list) {69$specs[] = $this->newDiffSpec($list['blocks']);70}7172$old_map = $specs[0]['map'];73$new_map = $specs[1]['map'];7475$old_list = $specs[0]['list'];76$new_list = $specs[1]['list'];7778$changeset = id(new PhabricatorDifferenceEngine())79->generateChangesetFromFileContent($old_list, $new_list);8081$hunk_parser = id(new DifferentialHunkParser())82->parseHunksForLineData($changeset->getHunks())83->reparseHunksForSpecialAttributes();8485$hunk_parser->generateVisibleBlocksMask(2);86$mask = $hunk_parser->getVisibleLinesMask();8788$old_lines = $hunk_parser->getOldLines();89$new_lines = $hunk_parser->getNewLines();9091$rows = array();9293$count = count($old_lines);94for ($ii = 0; $ii < $count; $ii++) {95$old_line = idx($old_lines, $ii);96$new_line = idx($new_lines, $ii);9798$is_visible = !empty($mask[$ii]);99100if ($old_line) {101$old_hash = rtrim($old_line['text'], "\n");102if (!strlen($old_hash)) {103// This can happen when one of the sources has no blocks.104$old_block = null;105} else {106$old_block = array_shift($old_map[$old_hash]);107$old_block108->setDifferenceType($old_line['type'])109->setIsVisible($is_visible);110}111} else {112$old_block = null;113}114115if ($new_line) {116$new_hash = rtrim($new_line['text'], "\n");117if (!strlen($new_hash)) {118$new_block = null;119} else {120$new_block = array_shift($new_map[$new_hash]);121$new_block122->setDifferenceType($new_line['type'])123->setIsVisible($is_visible);124}125} else {126$new_block = null;127}128129// If both lists are empty, we may generate a row which has two empty130// blocks.131if (!$old_block && !$new_block) {132continue;133}134135$rows[] = array(136$old_block,137$new_block,138);139}140141$this->layoutAvailableRowCount = count($rows);142143$rows = $this->revealIndexes($rows, true);144$rows = $this->sliceRows($rows);145146return $rows;147}148149public function newOneUpLayout() {150$rows = array();151$lists = $this->lists;152153$idx = 0;154while (true) {155$found_any = false;156157$row = array();158foreach ($lists as $list) {159$blocks = $list['blocks'];160$cell = idx($blocks, $idx);161162if ($cell !== null) {163$found_any = true;164}165166if ($cell) {167$rows[] = $cell;168}169}170171if (!$found_any) {172break;173}174175$idx++;176}177178$this->layoutAvailableRowCount = count($rows);179180$rows = $this->revealIndexes($rows, false);181$rows = $this->sliceRows($rows);182183return $rows;184}185186187private function newDiffSpec(array $blocks) {188$map = array();189$list = array();190191foreach ($blocks as $block) {192$hash = $block->getDifferenceHash();193194if (!isset($map[$hash])) {195$map[$hash] = array();196}197$map[$hash][] = $block;198199$list[] = $hash;200}201202return array(203'map' => $map,204'list' => implode("\n", $list)."\n",205);206}207208private function sliceRows(array $rows) {209$min = $this->rangeMin;210$max = $this->rangeMax;211212if ($min === null && $max === null) {213return $rows;214}215216if ($max === null) {217return array_slice($rows, $min, null, true);218}219220if ($min === null) {221$min = 0;222}223224return array_slice($rows, $min, $max - $min, true);225}226227private function revealIndexes(array $rows, $is_vector) {228if ($this->revealedIndexes === null) {229return $rows;230}231232foreach ($this->revealedIndexes as $index) {233if (!isset($rows[$index])) {234continue;235}236237if ($is_vector) {238foreach ($rows[$index] as $block) {239if ($block !== null) {240$block->setIsVisible(true);241}242}243} else {244$rows[$index]->setIsVisible(true);245}246}247248return $rows;249}250251}252253254