Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
<?php
require_once __DIR__ . '/BasePage.php';
require_once __DIR__ . '/../git/GitDiff.php';

class ComparePage extends BasePage {
  private $currentRepo;
  private $git;
  private $newSha;
  private $oldSha;

  public function __construct(
    array $repositories,
    array $currentRepo,
    Git $git,
    string $newSha,
    string $oldSha
  ) {
    $title = $currentRepo['name'] . ' - Compare';
    parent::__construct( $repositories, $title );

    $this->currentRepo = $currentRepo;
    $this->git         = $git;
    $this->newSha      = $newSha;
    $this->oldSha      = $oldSha;
  }

  public function render() {
    $this->renderLayout( function() {
      $shortNew = substr( $this->newSha, 0, 7 );
      $shortOld = substr( $this->oldSha, 0, 7 );

      $this->renderBreadcrumbs(
        $this->currentRepo,
        ["Compare $shortNew...$shortOld"]
      );

      $differ  = new GitDiff( $this->git );
      $changes = $differ->diff( $this->oldSha, $this->newSha );

      if( empty( $changes ) ) {
        echo '<div class="empty-state"><h3>No changes</h3>' .
             '<p>No differences.</p></div>';
      } else {
        foreach( $changes as $change ) {
          $this->renderDiffFile( $change );
        }
      }
    }, $this->currentRepo );
  }

  private function renderDiffFile( array $change ) {
    $typeMap = [
      'A' => 'added',
      'D' => 'deleted',
      'M' => 'modified'
    ];

    $statusClass = $typeMap[$change['type']] ?? 'modified';
    $path        = htmlspecialchars( $change['path'] );

    echo '<div class="diff-file">';
    echo '<div class="diff-header ' . $statusClass . '">';
    echo '<span class="diff-status-icon">' . $change['type'] . '</span> ';
    echo $path;
    echo '</div>';

    if( $change['is_binary'] ) {
      echo '<div class="diff-content binary">Binary file</div>';
    } elseif( !empty( $change['hunks'] ) ) {
      echo '<div class="diff-content">';
      echo '<table class="diff-table"><tbody>';

      foreach( $change['hunks'] as $line ) {
        $this->renderDiffLine( $line );
      }

      echo '</tbody></table>';
      echo '</div>';
    }

    echo '</div>';
  }

  private function renderDiffLine( array $line ) {
    if( $line['t'] === 'gap' ) {
      echo '<tr class="diff-gap"><td colspan="3">...</td></tr>';
    } else {
      $class = match( $line['t'] ) {
        '+'     => 'diff-add',
        '-'     => 'diff-del',
        default => ''
      };

      echo '<tr class="' . $class . '">';
      echo '<td class="diff-line-num">' . $line['no'] . '</td>';
      echo '<td class="diff-line-num">' . $line['nn'] . '</td>';
      echo '<td class="diff-code"><pre>' .
           htmlspecialchars( $line['l'] ) . '</pre></td>';
      echo '</tr>';
    }
  }
}