Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git

Reformats code

Author Dave Jarvis <email>
Date 2026-02-16 17:10:10 GMT-0800
Commit 01bdff3e50f6c71c33d35f25864ab5d6644ed75d
Parent 8b0e585
pages/BasePage.php
abstract class BasePage implements Page {
- protected $repositories;
- protected $title;
+ private $repositories;
+ private $title;
- public function __construct( array $repositories ) {
+ public function __construct( array $repositories, string $title = '' ) {
$this->repositories = $repositories;
+ $this->title = $title;
}
- protected function renderLayout( $contentCallback, $currentRepo = null ) {
+ protected function renderLayout(
+ $contentCallback,
+ array $currentRepo = []
+ ) {
+ $siteTitle = Config::SITE_TITLE;
+ $pageTitle = $this->title
+ ? ' - ' . htmlspecialchars( $this->title )
+ : '';
+
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title><?php
- echo Config::SITE_TITLE .
- ( $this->title ? ' - ' . htmlspecialchars( $this->title ) : '' );
- ?></title>
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+ <title><?php echo $siteTitle . $pageTitle; ?></title>
+ <link rel="stylesheet"
+ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="/styles/repo.css">
</head>
<body>
<div class="container">
<header>
<h1><?php echo Config::SITE_TITLE; ?></h1>
<nav class="nav">
<a href="<?php echo (new UrlBuilder())->build(); ?>">Home</a>
- <?php if( $currentRepo ):
- $safeName = $currentRepo['safe_name'];
- ?>
- <a href="<?php echo (new UrlBuilder())->withRepo( $safeName )->withAction( 'tree' )->build(); ?>">Files</a>
- <a href="<?php echo (new UrlBuilder())->withRepo( $safeName )->withAction( 'commits' )->build(); ?>">Commits</a>
- <a href="<?php echo (new UrlBuilder())->withRepo( $safeName )->withAction( 'tags' )->build(); ?>">Tags</a>
+ <?php if( $currentRepo ): ?>
+ <?php $safeName = $currentRepo['safe_name']; ?>
+ <a href="<?php echo (new UrlBuilder())
+ ->withRepo( $safeName )
+ ->withAction( 'tree' )
+ ->build(); ?>">Files</a>
+ <a href="<?php echo (new UrlBuilder())
+ ->withRepo( $safeName )
+ ->withAction( 'commits' )
+ ->build(); ?>">Commits</a>
+ <a href="<?php echo (new UrlBuilder())
+ ->withRepo( $safeName )
+ ->withAction( 'tags' )
+ ->build(); ?>">Tags</a>
<?php endif; ?>
<?php if( $currentRepo ): ?>
<div class="repo-selector">
<label>Repository:</label>
- <select onchange="<?php echo (new UrlBuilder())->withSwitcher( 'this.value' )->build(); ?>">
+ <select onchange="<?php echo (new UrlBuilder())
+ ->withSwitcher( 'this.value' )
+ ->build(); ?>">
<?php foreach( $this->repositories as $r ): ?>
- <option value="<?php echo htmlspecialchars( $r['safe_name'] ); ?>"
- <?php echo $r['safe_name'] === $currentRepo['safe_name'] ? 'selected' : ''; ?>>
+ <option
+ value="<?php echo htmlspecialchars( $r['safe_name'] ); ?>"
+ <?php
+ echo $r['safe_name'] === $currentRepo['safe_name']
+ ? 'selected'
+ : '';
+ ?>>
<?php echo htmlspecialchars( $r['name'] ); ?>
</option>
}
- protected function renderBreadcrumbs( $repo, $trail = [] ) {
+ protected function renderBreadcrumbs( array $repo, array $trail = [] ) {
$repoUrl = (new UrlBuilder())->withRepo( $repo['safe_name'] )->build();
pages/CommitsPage.php
string $hash
) {
- parent::__construct( $repositories );
+ parent::__construct( $repositories, $currentRepo['name'] );
+
$this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->hash = $hash;
- $this->title = $currentRepo['name'];
+ $this->git = $git;
+ $this->hash = $hash;
}
public function render() {
$this->renderLayout( function() {
$main = $this->git->getMainBranch();
if( !$main ) {
echo '<div class="empty-state"><h3>No branches</h3>' .
'<p>Empty repository.</p></div>';
- return;
- }
+ } else {
+ $this->renderBreadcrumbs( $this->currentRepo, ['Commits'] );
- $this->renderBreadcrumbs( $this->currentRepo, ['Commits'] );
+ echo '<h2>Commit History <span class="branch-badge">' .
+ htmlspecialchars( $main['name'] ) . '</span></h2>';
+ echo '<div class="commit-list">';
- echo '<h2>Commit History <span class="branch-badge">' .
- htmlspecialchars( $main['name'] ) . '</span></h2>';
- echo '<div class="commit-list">';
+ $start = $this->hash ?: $main['hash'];
- $start = $this->hash ?: $main['hash'];
+ $this->git->history( $start, 100, function( $commit ) {
+ $msg = htmlspecialchars( explode( "\n", $commit->message )[0] );
- $this->git->history( $start, 100, function( $commit ) {
- $msg = htmlspecialchars( explode( "\n", $commit->message )[0] );
+ $url = (new UrlBuilder())
+ ->withRepo( $this->currentRepo['safe_name'] )
+ ->withAction( 'commit' )
+ ->withHash( $commit->sha )
+ ->build();
- $url = (new UrlBuilder())
- ->withRepo( $this->currentRepo['safe_name'] )
- ->withAction( 'commit' )
- ->withHash( $commit->sha )
- ->build();
+ echo '<div class="commit-row">';
+ echo '<a href="' . $url . '" class="sha">' .
+ substr( $commit->sha, 0, 7 ) . '</a>';
+ echo '<span class="message">' . $msg . '</span>';
+ echo '<span class="meta">' .
+ htmlspecialchars( $commit->author ) .
+ ' &bull; ' . date( 'Y-m-d', $commit->date ) . '</span>';
+ echo '</div>';
+ } );
- echo '<div class="commit-row">';
- echo '<a href="' . $url . '" class="sha">' . substr( $commit->sha, 0, 7 ) . '</a>';
- echo '<span class="message">' . $msg . '</span>';
- echo '<span class="meta">' . htmlspecialchars( $commit->author ) .
- ' &bull; ' . date( 'Y-m-d', $commit->date ) . '</span>';
echo '</div>';
- } );
-
- echo '</div>';
+ }
}, $this->currentRepo );
}
pages/ComparePage.php
string $oldSha
) {
- parent::__construct( $repositories );
+ $title = $currentRepo['name'] . ' - Compare';
+ parent::__construct( $repositories, $title );
+
$this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->newSha = $newSha;
- $this->oldSha = $oldSha;
- $this->title = $currentRepo['name'] . ' - Compare';
+ $this->git = $git;
+ $this->newSha = $newSha;
+ $this->oldSha = $oldSha;
}
);
- $differ = new GitDiff( $this->git );
+ $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>';
- return;
- }
-
- foreach( $changes as $change ) {
- $this->renderDiffFile( $change );
+ } else {
+ foreach( $changes as $change ) {
+ $this->renderDiffFile( $change );
+ }
}
}, $this->currentRepo );
$statusClass = $typeMap[$change['type']] ?? 'modified';
- $path = htmlspecialchars( $change['path'] );
+ $path = htmlspecialchars( $change['path'] );
echo '<div class="diff-file">';
if( isset( $line['t'] ) && $line['t'] === 'gap' ) {
echo '<tr class="diff-gap"><td colspan="3">...</td></tr>';
- return;
- }
-
- $class = match( $line['t'] ) {
- '+' => 'diff-add',
- '-' => 'diff-del',
- default => ''
- };
+ } 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>';
+ 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>';
+ }
}
}
pages/DiffPage.php
string $hash
) {
- parent::__construct( $repositories );
+ parent::__construct( $repositories, substr( $hash, 0, 7 ) );
+
$this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->hash = $hash;
- $this->title = substr( $hash, 0, 7 );
+ $this->git = $git;
+ $this->hash = $hash;
}
public function render() {
$this->renderLayout( function() {
$commitData = $this->git->read( $this->hash );
$diffEngine = new GitDiff( $this->git );
- $lines = explode( "\n", $commitData );
- $msg = '';
- $isMsg = false;
- $headers = [];
+ $lines = explode( "\n", $commitData );
+ $msg = '';
+ $isMsg = false;
+ $headers = [];
foreach( $lines as $line ) {
'<a href="' . $commitsUrl . '">Commits</a>',
substr( $this->hash, 0, 7 )
- ]);
+ ] );
$author = $headers['author'] ?? 'Unknown';
$author = preg_replace( '/<[^>]+>/', '<email>', $author );
echo '<div class="commit-details">';
echo '<div class="commit-header">';
- echo '<h1 class="commit-title">' . htmlspecialchars( trim( $msg ) ) . '</h1>';
+ echo '<h1 class="commit-title">' .
+ htmlspecialchars( trim( $msg ) ) . '</h1>';
echo '<div class="commit-info">';
- echo '<div class="commit-info-row"><span class="commit-info-label">Author</span>' .
- '<span class="commit-author">' . htmlspecialchars( $author ) . '</span></div>';
- echo '<div class="commit-info-row"><span class="commit-info-label">Commit</span>' .
- '<span class="commit-info-value">' . $this->hash . '</span></div>';
+ echo '<div class="commit-info-row">' .
+ '<span class="commit-info-label">Author</span>' .
+ '<span class="commit-author">' .
+ htmlspecialchars( $author ) . '</span></div>';
+ echo '<div class="commit-info-row">' .
+ '<span class="commit-info-label">Commit</span>' .
+ '<span class="commit-info-value">' .
+ $this->hash . '</span></div>';
if( isset( $headers['parent'] ) ) {
$url = (new UrlBuilder())
->withRepo( $this->currentRepo['safe_name'] )
->withAction( 'commit' )
->withHash( $headers['parent'] )
->build();
- echo '<div class="commit-info-row"><span class="commit-info-label">Parent</span>' .
+ echo '<div class="commit-info-row">' .
+ '<span class="commit-info-label">Parent</span>' .
'<span class="commit-info-value">';
echo '<a href="' . $url . '" class="parent-link">' .
private function renderFileDiff( $change ) {
- $statusIcon = 'fa-file';
+ $statusIcon = 'fa-file';
$statusClass = '';
if( $change['type'] === 'A' ) {
- $statusIcon = 'fa-plus-circle';
+ $statusIcon = 'fa-plus-circle';
$statusClass = 'status-add';
}
if( $change['type'] === 'D' ) {
- $statusIcon = 'fa-minus-circle';
+ $statusIcon = 'fa-minus-circle';
$statusClass = 'status-del';
}
if( $change['type'] === 'M' ) {
- $statusIcon = 'fa-pencil-alt';
+ $statusIcon = 'fa-pencil-alt';
$statusClass = 'status-mod';
}
echo '<div class="diff-file">';
echo '<div class="diff-header">';
echo '<span class="diff-status ' . $statusClass . '">' .
'<i class="fa ' . $statusIcon . '"></i></span>';
- echo '<span class="diff-path">' . htmlspecialchars( $change['path'] ) . '</span>';
+ echo '<span class="diff-path">' .
+ htmlspecialchars( $change['path'] ) . '</span>';
echo '</div>';
$class = 'diff-ctx';
- $char = ' ';
+ $char = ' ';
if( $line['t'] === '+' ) {
$class = 'diff-add';
- $char = '+';
+ $char = '+';
}
if( $line['t'] === '-' ) {
$class = 'diff-del';
- $char = '-';
+ $char = '-';
}
echo '<tr class="' . $class . '">';
echo '<td class="diff-num" data-num="' . $line['no'] . '"></td>';
echo '<td class="diff-num" data-num="' . $line['nn'] . '"></td>';
- echo '<td class="diff-code"><span class="diff-marker">' . $char . '</span>' .
- htmlspecialchars( $line['l'] ) . '</td>';
+ echo '<td class="diff-code"><span class="diff-marker">' .
+ $char . '</span>' . htmlspecialchars( $line['l'] ) . '</td>';
echo '</tr>';
}
pages/FilePage.php
class FilePage extends BasePage {
private const MAX_HIGHLIGHT_SIZE = 65536;
- private const MAX_DISPLAY_SIZE = 524288;
+ private const MAX_DISPLAY_SIZE = 524288;
private $currentRepo;
string $path = ''
) {
- parent::__construct( $repositories );
+ parent::__construct( $repositories, $currentRepo['name'] );
+
$this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->hash = $hash ?: 'HEAD';
- $this->path = $path;
- $this->title = $currentRepo['name'];
+ $this->git = $git;
+ $this->hash = $hash ?: 'HEAD';
+ $this->path = $path;
}
}
- private function isExactFileMatch($entries) {
- return count( $entries ) === 1 &&
- $entries[0]->isName( basename( $this->path ) ) &&
- !$entries[0]->isDir;
+ private function isExactFileMatch( $entries ) {
+ return count( $entries ) === 1 &&
+ $entries[0]->isName( basename( $this->path ) ) &&
+ !$entries[0]->isDir;
}
echo '<table class="file-list-table">';
- echo '<thead><tr><th></th><th>Name</th><th class="file-mode-cell">Mode</th><th class="file-size-cell">Size</th></tr></thead>';
+ echo '<thead><tr><th></th><th>Name</th>' .
+ '<th class="file-mode-cell">Mode</th>' .
+ '<th class="file-size-cell">Size</th></tr></thead>';
echo '<tbody>';
private function renderBlob( $targetHash ) {
$filename = $this->path;
- $file = $this->git->readFile( $targetHash, $filename );
- $size = $this->git->getObjectSize( $targetHash, $filename );
+ $file = $this->git->readFile( $targetHash, $filename );
+ $size = $this->git->getObjectSize( $targetHash, $filename );
- $renderer = new HtmlFileRenderer( $this->currentRepo['safe_name'], dirname($filename), $targetHash );
+ $renderer = new HtmlFileRenderer(
+ $this->currentRepo['safe_name'],
+ dirname( $filename ),
+ $targetHash
+ );
$this->emitBreadcrumbs( $targetHash, 'File', $filename );
if( $size === 0 && !$file ) {
- echo '<div class="empty-state">File not found.</div>';
- return;
- }
+ echo '<div class="empty-state">File not found.</div>';
+ } else {
+ $rawUrl = (new UrlBuilder())
+ ->withRepo( $this->currentRepo['safe_name'] )
+ ->withAction( 'raw' )
+ ->withHash( $targetHash )
+ ->withName( $filename )
+ ->build();
- $rawUrl = (new UrlBuilder())
- ->withRepo( $this->currentRepo['safe_name'] )
- ->withAction( 'raw' )
- ->withHash( $targetHash )
- ->withName( $filename )
- ->build();
+ if( !$file->renderMedia( $renderer, $rawUrl ) ) {
+ if( $file->isText() ) {
+ if( $size > self::MAX_DISPLAY_SIZE ) {
+ ob_start();
+ $file->renderSize( $renderer );
+ $sizeStr = ob_get_clean();
+ $this->renderDownloadState(
+ $targetHash,
+ "File is too large to display ($sizeStr)."
+ );
+ } else {
+ $content = '';
+ $this->git->stream(
+ $targetHash,
+ function( $d ) use ( &$content ) {
+ $content .= $d;
+ },
+ $filename
+ );
- if( !$file->renderMedia( $renderer, $rawUrl ) ) {
- if( $file->isText() ) {
- if( $size > self::MAX_DISPLAY_SIZE ) {
- ob_start();
- $file->renderSize( $renderer );
- $sizeStr = ob_get_clean();
- $this->renderDownloadState( $targetHash, "File is too large to display ($sizeStr)." );
+ echo '<div class="blob-content"><pre class="blob-code">' .
+ ($size > self::MAX_HIGHLIGHT_SIZE
+ ? htmlspecialchars( $content )
+ : $file->highlight( $renderer, $content )) .
+ '</pre></div>';
+ }
} else {
- $content = '';
- $this->git->stream( $targetHash, function( $d ) use ( &$content ) {
- $content .= $d;
- }, $filename );
-
- echo '<div class="blob-content"><pre class="blob-code">' .
- ($size > self::MAX_HIGHLIGHT_SIZE
- ? htmlspecialchars( $content )
- : $file->highlight( $renderer, $content )) .
- '</pre></div>';
+ $this->renderDownloadState(
+ $targetHash,
+ "This is a binary file."
+ );
}
- } else {
- $this->renderDownloadState( $targetHash, "This is a binary file." );
}
}
if( $path ) {
$parts = explode( '/', trim( $path, '/' ) );
- $acc = '';
+ $acc = '';
foreach( $parts as $idx => $part ) {
->build();
- $trail[] = '<a href="' . $url . '">' . htmlspecialchars( $part ) . '</a>';
+ $trail[] = '<a href="' . $url . '">' .
+ htmlspecialchars( $part ) . '</a>';
}
}
pages/HomePage.php
class HomePage extends BasePage {
+ private $repositories;
private $git;
public function __construct( array $repositories, Git $git ) {
parent::__construct( $repositories );
- $this->git = $git;
+ $this->repositories = $repositories;
+ $this->git = $git;
}
public function render() {
$this->renderLayout( function() {
echo '<h2>Repositories</h2>';
if( empty( $this->repositories ) ) {
echo '<div class="empty-state">No repositories found.</div>';
- return;
- }
+ } else {
+ echo '<div class="repo-grid">';
- echo '<div class="repo-grid">';
+ foreach( $this->repositories as $repo ) {
+ $this->renderRepoCard( $repo );
+ }
- foreach( $this->repositories as $repo ) {
- $this->renderRepoCard( $repo );
+ echo '</div>';
}
-
- echo '</div>';
} );
}
private function renderRepoCard( $repo ) {
$this->git->setRepository( $repo['path'] );
- $main = $this->git->getMainBranch();
+ $main = $this->git->getMainBranch();
$stats = [
'branches' => 0,
- 'tags' => 0
+ 'tags' => 0
];
$branchLabel = $stats['branches'] === 1 ? 'branch' : 'branches';
- $tagLabel = $stats['tags'] === 1 ? 'tag' : 'tags';
+ $tagLabel = $stats['tags'] === 1 ? 'tag' : 'tags';
echo $stats['branches'] . ' ' . $branchLabel . ', ' .
pages/Page.php
<?php
interface Page {
- public function render();
+ public function render();
}
pages/TagsPage.php
Git $git
) {
- parent::__construct( $repositories );
+ parent::__construct(
+ $repositories,
+ $currentRepo['name'] . ' - Tags'
+ );
+
$this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->title = $currentRepo['name'] . ' - Tags';
+ $this->git = $git;
}
echo '<p>No tags found.</p>';
} else {
- $renderer = new HtmlTagRenderer( $this->currentRepo['safe_name'] );
+ $renderer = new HtmlTagRenderer(
+ $this->currentRepo['safe_name']
+ );
echo '<table class="tag-table">';
$count = count( $tags );
for( $i = 0; $i < $count; $i++ ) {
- $tag = $tags[$i];
+ $tag = $tags[$i];
$prevTag = $tags[$i + 1] ?? null;
$tag->render( $renderer, $prevTag );
Delta 208 lines added, 157 lines removed, 51-line increase