Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/differential/parser/changeset/DifferentialChangesetParser.php b/src/applications/differential/parser/changeset/DifferentialChangesetParser.php
index 605803b212..1c71ce87c4 100644
--- a/src/applications/differential/parser/changeset/DifferentialChangesetParser.php
+++ b/src/applications/differential/parser/changeset/DifferentialChangesetParser.php
@@ -1,1305 +1,1316 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DifferentialChangesetParser {
protected $visible = array();
protected $new = array();
protected $old = array();
protected $intra = array();
protected $newRender = null;
protected $oldRender = null;
protected $parsedHunk = false;
protected $filename = null;
protected $filetype = null;
protected $changesetID = null;
protected $missingOld = array();
protected $missingNew = array();
protected $comments = array();
protected $specialAttributes = array();
protected $changeset;
protected $whitespaceMode = null;
protected $subparser;
protected $oldChangesetID = null;
protected $noHighlight;
const CACHE_VERSION = 4;
const ATTR_GENERATED = 'attr:generated';
const ATTR_DELETED = 'attr:deleted';
const ATTR_UNCHANGED = 'attr:unchanged';
const ATTR_WHITELINES = 'attr:white';
const LINES_CONTEXT = 8;
const WHITESPACE_SHOW_ALL = 'show-all';
const WHITESPACE_IGNORE_TRAILING = 'ignore-trailing';
const WHITESPACE_IGNORE_ALL = 'ignore-all';
public function setChangeset($changeset) {
$this->changeset = $changeset;
$this->setFilename($changeset->getFilename());
$this->setChangesetID($changeset->getID());
return $this;
}
public function setWhitespaceMode($whitespace_mode) {
$this->whitespaceMode = $whitespace_mode;
return $this;
}
public function setOldChangesetID($old_changeset_id) {
$this->oldChangesetID = $old_changeset_id;
return $this;
}
public function setChangesetID($changeset_id) {
$this->changesetID = $changeset_id;
return $this;
}
public function getChangesetID() {
return $this->changesetID;
}
public function setFilename($filename) {
$this->filename = $filename;
if (strpos($filename, '.', 1) !== false) {
$this->filetype = end(explode('.', $filename));
}
}
public function parseHunk(DifferentialHunk $hunk) {
$this->parsedHunk = true;
$lines = $hunk->getChanges();
// Flatten UTF-8 into "\0". We don't support UTF-8 because the diffing
// algorithms are byte-oriented (not character oriented) and everyone seems
// to be in agreement that it's fairly reasonable not to allow UTF-8 in
// source files. These bytes will later be replaced with a "?" glyph, but
// in the meantime we replace them with "\0" since Pygments is happy to
// deal with that.
$lines = preg_replace('/[\x80-\xFF]/', "\0", $lines);
$lines = str_replace(
array("\t", "\r\n", "\r"),
array(' ', "\n", "\n"),
$lines);
$lines = explode("\n", $lines);
$types = array();
foreach ($lines as $line_index => $line) {
$lines[$line_index] = $line;
if (isset($line[0])) {
$char = $line[0];
if ($char == ' ') {
$types[$line_index] = null;
} else if ($char == '\\' && $line_index > 0) {
$types[$line_index] = $types[$line_index - 1];
} else {
$types[$line_index] = $char;
}
} else {
$types[$line_index] = null;
}
}
$old_line = $hunk->getOldOffset();
$new_line = $hunk->getNewOffset();
$num_lines = count($lines);
if ($old_line > 1) {
$this->missingOld[$old_line] = true;
} else if ($new_line > 1) {
$this->missingNew[$new_line] = true;
}
for ($cursor = 0; $cursor < $num_lines; $cursor++) {
$type = $types[$cursor];
$data = array(
'type' => $type,
'text' => (string)substr($lines[$cursor], 1),
'line' => $new_line,
);
switch ($type) {
case '+':
$this->new[] = $data;
++$new_line;
break;
case '-':
$data['line'] = $old_line;
$this->old[] = $data;
++$old_line;
break;
default:
$this->new[] = $data;
$data['line'] = $old_line;
$this->old[] = $data;
++$new_line;
++$old_line;
break;
}
}
}
public function getDisplayLine($offset, $length) {
$start = 1;
for ($ii = $offset; $ii > 0; $ii--) {
if ($this->new[$ii] && $this->new[$ii]['line']) {
$start = $this->new[$ii]['line'];
break;
}
}
$end = $start;
for ($ii = $offset + $length; $ii < count($this->new); $ii++) {
if ($this->new[$ii] && $this->new[$ii]['line']) {
$end = $this->new[$ii]['line'];
break;
}
}
return "{$start},{$end}";
}
public function parseInlineComment(DifferentialInlineComment $comment) {
$this->comments[] = $comment;
return $this;
}
public function process() {
$old = array();
$new = array();
$n = 0;
$this->old = array_reverse($this->old);
$this->new = array_reverse($this->new);
$whitelines = false;
$changed = false;
$skip_intra = array();
while (count($this->old) || count($this->new)) {
$o_desc = array_pop($this->old);
$n_desc = array_pop($this->new);
$oend = end($this->old);
if ($oend) {
$o_next = $oend['type'];
} else {
$o_next = null;
}
$nend = end($this->new);
if ($nend) {
$n_next = $nend['type'];
} else {
$n_next = null;
}
if ($o_desc) {
$o_type = $o_desc['type'];
} else {
$o_type = null;
}
if ($n_desc) {
$n_type = $n_desc['type'];
} else {
$n_type = null;
}
if (($o_type != null) && ($n_type == null)) {
$old[] = $o_desc;
$new[] = null;
if ($n_desc) {
array_push($this->new, $n_desc);
}
$changed = true;
continue;
}
if (($n_type != null) && ($o_type == null)) {
$old[] = null;
$new[] = $n_desc;
if ($o_desc) {
array_push($this->old, $o_desc);
}
$changed = true;
continue;
}
if ($this->whitespaceMode != self::WHITESPACE_SHOW_ALL) {
$similar = false;
switch ($this->whitespaceMode) {
case self::WHITESPACE_IGNORE_TRAILING:
if (rtrim($o_desc['text']) == rtrim($n_desc['text'])) {
$similar = true;
}
break;
}
if ($similar) {
$o_desc['type'] = null;
$n_desc['type'] = null;
$skip_intra[count($old)] = true;
$whitelines = true;
} else {
$changed = true;
}
} else {
$changed = true;
}
$old[] = $o_desc;
$new[] = $n_desc;
}
$this->old = $old;
$this->new = $new;
if ($this->subparser && false) { // TODO: This is bugged
// Use the subparser's side-by-side line information -- notably, the
// change types -- but replace all the line text with ours. This lets us
// render whitespace-only changes without marking them as different.
$old = $this->subparser->old;
$new = $this->subparser->new;
$old_text = ipull($this->old, 'text', 'line');
$new_text = ipull($this->new, 'text', 'line');
foreach ($old as $k => $desc) {
if (empty($desc)) {
continue;
}
$old[$k]['text'] = idx($old_text, $desc['line']);
}
foreach ($new as $k => $desc) {
if (empty($desc)) {
continue;
}
$new[$k]['text'] = idx($new_text, $desc['line']);
}
$this->old = $old;
$this->new = $new;
}
$min_length = min(count($this->old), count($this->new));
for ($ii = 0; $ii < $min_length; $ii++) {
if ($this->old[$ii] || $this->new[$ii]) {
- $otext = idx($this->old[$ii], 'text', '');
- $ntext = idx($this->new[$ii], 'text', '');
+ if (isset($this->old[$ii]['text'])) {
+ $otext = $this->old[$ii]['text'];
+ } else {
+ $otext = '';
+ }
+ if (isset($this->new[$ii]['text'])) {
+ $ntext = $this->new[$ii]['text'];
+ } else {
+ $ntext = '';
+ }
if ($otext != $ntext && empty($skip_intra[$ii])) {
$this->intra[$ii] = ArcanistDiffUtils::generateIntralineDiff(
$otext,
$ntext);
}
}
}
$lines_context = self::LINES_CONTEXT;
$max_length = max(count($this->old), count($this->new));
$old = $this->old;
$new = $this->new;
$visible = false;
$last = 0;
for ($cursor = -$lines_context; $cursor < $max_length; $cursor++) {
$offset = $cursor + $lines_context;
if ((isset($old[$offset]) && $old[$offset]['type']) ||
(isset($new[$offset]) && $new[$offset]['type'])) {
$visible = true;
$last = $offset;
} else if ($cursor > $last + $lines_context) {
$visible = false;
}
if ($visible && $cursor > 0) {
$this->visible[$cursor] = 1;
}
}
$old_corpus = ipull($this->old, 'text');
$old_corpus_block = implode("\n", $old_corpus);
$new_corpus = ipull($this->new, 'text');
$new_corpus_block = implode("\n", $new_corpus);
if ($this->noHighlight) {
$this->oldRender = explode("\n", phutil_escape_html($old_corpus_block));
$this->newRender = explode("\n", phutil_escape_html($new_corpus_block));
} else {
$this->oldRender = $this->sourceHighlight($this->old, $old_corpus_block);
$this->newRender = $this->sourceHighlight($this->new, $new_corpus_block);
}
$this->applyIntraline(
$this->oldRender,
ipull($this->intra, 0),
$old_corpus);
$this->applyIntraline(
$this->newRender,
ipull($this->intra, 1),
$new_corpus);
$this->tokenHighlight($this->oldRender);
$this->tokenHighlight($this->newRender);
$unchanged = false;
if ($this->subparser && false) {
$unchanged = $this->subparser->isUnchanged();
$whitelines = $this->subparser->isWhitespaceOnly();
} else if (!$changed) {
$filetype = $this->changeset->getFileType();
if ($filetype == DifferentialChangeType::FILE_TEXT ||
$filetype == DifferentialChangeType::FILE_SYMLINK) {
$unchanged = true;
}
}
$generated = (strpos($new_corpus_block, '@'.'generated') !== false);
$this->specialAttributes = array(
self::ATTR_GENERATED => $generated,
self::ATTR_UNCHANGED => $unchanged,
self::ATTR_DELETED => array_filter($this->old) &&
!array_filter($this->new),
self::ATTR_WHITELINES => $whitelines
);
}
public function loadCache() {
if (!$this->changesetID) {
return false;
}
$data = null;
/*
$data = queryfx_one(
smc_get_db('cdb.differential', 'r'),
'SELECT * FROM changeset_parse_cache WHERE id = %d',
$this->changesetID);
*/
if (!$data) {
return false;
}
$data = json_decode($data['cache'], true);
if (!is_array($data) || !$data) {
return false;
}
foreach (self::getCacheableProperties() as $cache_key) {
if (!array_key_exists($cache_key, $data)) {
// If we're missing a cache key, assume we're looking at an old cache
// and ignore it.
return false;
}
}
if ($data['cacheVersion'] !== self::CACHE_VERSION) {
return false;
}
unset($data['cacheVersion'], $data['cacheHost']);
$cache_prop = array_select_keys($data, self::getCacheableProperties());
foreach ($cache_prop as $cache_key => $v) {
$this->$cache_key = $v;
}
return true;
}
protected static function getCacheableProperties() {
return array(
'visible',
'new',
'old',
'intra',
'newRender',
'oldRender',
'specialAttributes',
'missingOld',
'missingNew',
'cacheVersion',
'cacheHost',
);
}
public function saveCache() {
if (!$this->changesetID) {
return false;
}
$cache = array();
foreach (self::getCacheableProperties() as $cache_key) {
switch ($cache_key) {
case 'cacheVersion':
$cache[$cache_key] = self::CACHE_VERSION;
break;
case 'cacheHost':
$cache[$cache_key] = php_uname('n');
break;
default:
$cache[$cache_key] = $this->$cache_key;
break;
}
}
$cache = json_encode($cache);
try {
/*
queryfx(
smc_get_db('cdb.differential', 'w'),
'INSERT INTO changeset_parse_cache (id, cache) VALUES (%d, %s)
ON DUPLICATE KEY UPDATE cache = VALUES(cache)',
$this->changesetID,
$cache);
*/
} catch (QueryException $ex) {
// TODO: uhoh
}
}
public function isGenerated() {
return idx($this->specialAttributes, self::ATTR_GENERATED, false);
}
public function isDeleted() {
return idx($this->specialAttributes, self::ATTR_DELETED, false);
}
public function isUnchanged() {
return idx($this->specialAttributes, self::ATTR_UNCHANGED, false);
}
public function isWhitespaceOnly() {
return idx($this->specialAttributes, self::ATTR_WHITELINES, false);
}
public function getLength() {
return max(count($this->old), count($this->new));
}
protected function applyIntraline(&$render, $intra, $corpus) {
foreach ($render as $key => $text) {
if (isset($intra[$key])) {
$render[$key] = ArcanistDiffUtils::applyIntralineDiff(
$text,
$intra[$key]);
}
if (isset($corpus[$key]) && strlen($corpus[$key]) > 80) {
$render[$key] = $this->lineWrap($render[$key]);
}
}
}
protected function lineWrap($l) {
$c = 0;
$len = strlen($l);
$ins = array();
for ($ii = 0; $ii < $len; ++$ii) {
if ($l[$ii] == '&') {
do {
++$ii;
} while ($l[$ii] != ';');
++$c;
} else if ($l[$ii] == '<') {
do {
++$ii;
} while ($l[$ii] != '>');
} else {
++$c;
}
if ($c == 80) {
$ins[] = ($ii + 1);
$c = 0;
}
}
while (($pos = array_pop($ins))) {
$l = substr_replace(
$l,
"<span class=\"over-the-line\">\xE2\xAC\x85</span><br />",
$pos,
0);
}
return $l;
}
protected function tokenHighlight(&$render) {
foreach ($render as $key => $text) {
$render[$key] = str_replace(
"\0",
'<span class="uu">'."\xEF\xBF\xBD".'</span>',
$text);
}
}
protected function sourceHighlight($data, $corpus) {
-// $result = highlight_code($corpus, $this->filetype);
- $result = phutil_escape_html($corpus);
-
+ $result = $this->highlightEngine->highlightSource(
+ $this->filetype,
+ $corpus);
+
$result_lines = explode("\n", $result);
foreach ($data as $key => $info) {
if (!$info) {
unset($result_lines[$key]);
}
}
return $result_lines;
}
private function tryCacheStuff() {
$whitespace_mode = $this->whitespaceMode;
switch ($whitespace_mode) {
case self::WHITESPACE_SHOW_ALL:
case self::WHITESPACE_IGNORE_TRAILING:
break;
default:
$whitespace_mode = self::WHITESPACE_IGNORE_ALL;
break;
}
$skip_cache = ($whitespace_mode != self::WHITESPACE_IGNORE_ALL);
$this->whitespaceMode = $whitespace_mode;
$changeset = $this->changeset;
if ($changeset->getFileType() == DifferentialChangeType::FILE_TEXT ||
$changeset->getFileType() == DifferentialChangeType::FILE_SYMLINK) {
if ($skip_cache || !$this->loadCache()) {
if ($this->whitespaceMode == self::WHITESPACE_IGNORE_ALL) {
// Huge mess. Generate a "-bw" (ignore all whitespace changes) diff,
// parse it out, and then play a shell game with the parsed format
// in process() so we highlight only changed lines but render
// whitespace differences. If we don't do this, we either fail to
// render whitespace changes (which is incredibly confusing,
// especially for python) or often produce a much larger set of
// differences than necessary.
$old_tmp = new TempFile();
$new_tmp = new TempFile();
Filesystem::writeFile($old_tmp, $changeset->makeOldFile());
Filesystem::writeFile($new_tmp, $changeset->makeNewFile());
list($err, $diff) = exec_manual(
'diff -bw -U9999 %s %s',
$old_tmp,
$new_tmp);
if (!strlen($diff)) {
// If there's no diff text, that means the files are identical
// except for whitespace changes. Build a synthetic, changeless
// diff. TODO: this is incredibly hacky.
$entire_file = explode("\n", $changeset->makeOldFile());
foreach ($entire_file as $k => $line) {
$entire_file[$k] = ' '.$line;
}
$len = count($entire_file);
$entire_file = implode("\n", $entire_file);
$diff = <<<EOSYNTHETIC
--- ignored 9999-99-99
+++ ignored 9999-99-99
@@ -{$len},{$len} +{$len},{$len} @@
{$entire_file}
EOSYNTHETIC;
}
$changes = id(new ArcanistDiffParser())->parseDiff($diff);
$diff = DifferentialDiff::newFromRawChanges($changes);
$alt_changeset = reset($diff->getChangesets());
$this->subparser = new DifferentialChangesetParser();
$this->subparser->setChangeset($alt_changeset);
$this->subparser->setWhitespaceMode(self::WHITESPACE_IGNORE_TRAILING);
}
foreach ($changeset->getHunks() as $hunk) {
$this->parseHunk($hunk);
}
$this->process();
if (!$skip_cache) {
$this->saveCache();
}
}
}
}
public function render(
ViewerContext $viewer_context = null,
$range_start = null,
$range_len = null,
$mask_force = array()) {
+ $this->highlightEngine = new PhutilDefaultSyntaxHighlighterEngine();
+
$this->tryCacheStuff();
$changeset_id = $this->changesetID;
$feedback_mask = array();
switch ($this->changeset->getFileType()) {
case DifferentialChangeType::FILE_IMAGE:
$old = null;
$cur = null;
$metadata = $this->changeset->getMetadata();
$data = idx($metadata, 'attachment-data');
$old_phid = idx($metadata, 'old:binary-phid');
$new_phid = idx($metadata, 'new:binary-phid');
if ($old_phid || $new_phid) {
if ($old_phid) {
$old_uri = PhabricatorFileURI::getViewURIForPHID($old_phid);
$old = phutil_render_tag(
'img',
array(
'src' => $old_uri,
));
}
if ($new_phid) {
$new_uri = PhabricatorFileURI::getViewURIForPHID($new_phid);
$cur = phutil_render_tag(
'img',
array(
'src' => $new_uri,
));
}
}
$output = $this->renderChangesetTable(
$this->changeset,
'<tr>'.
'<th></th>'.
'<td class="differential-old-image">'.
'<div class="differential-image-stage">'.
$old.
'</div>'.
'</td>'.
'<th></th>'.
'<td class="differential-new-image">'.
'<div class="differential-image-stage">'.
$cur.
'</div>'.
'</td>'.
'</tr>');
return $output;
case DifferentialChangeType::FILE_DIRECTORY:
case DifferentialChangeType::FILE_BINARY:
$output = $this->renderChangesetTable($this->changeset, null);
return $output;
}
$shield = null;
if ($range_start === null && $range_len === null) {
if ($this->isGenerated()) {
$shield = $this->renderShield(
"This file contains generated code, which does not normally need ".
"to be reviewed.",
true);
} else if ($this->isUnchanged()) {
if ($this->isWhitespaceOnly()) {
$shield = $this->renderShield(
"This file was changed only by adding or removing trailing ".
"whitespace.",
false);
} else {
$shield = $this->renderShield(
"The contents of this file were not changed.",
false);
}
} else if ($this->isDeleted()) {
$shield = $this->renderShield(
"This file was completely deleted.",
true);
} else if ($this->changeset->getAffectedLineCount() > 2500) {
$lines = number_format($this->changeset->getAffectedLineCount());
$shield = $this->renderShield(
"This file has a very large number of changes ({$lines} lines).",
true);
} else if (preg_match('/\.sql3$/', $this->changeset->getFilename())) {
$shield = $this->renderShield(
".sql3 files are hidden by default.",
true);
}
}
if ($shield) {
return $this->renderChangesetTable($this->changeset, $shield);
}
$old_comments = array();
$new_comments = array();
$old_mask = array();
$new_mask = array();
$feedback_mask = array();
$handles = array();
if ($this->comments) {
foreach ($this->comments as $comment) {
$start = max($comment->getLineNumber() - self::LINES_CONTEXT, 0);
$end = $comment->getFinalLine() + self::LINES_CONTEXT;
$new = $this->isCommentInNewFile($comment);
for ($ii = $start; $ii <= $end; $ii++) {
if ($new) {
$new_mask[$ii] = true;
} else {
$old_mask[$ii] = true;
}
}
}
foreach ($this->old as $ii => $old) {
if (isset($old['line']) && isset($old_mask[$old['line']])) {
$feedback_mask[$ii] = true;
}
}
foreach ($this->new as $ii => $new) {
if (isset($new['line']) && isset($new_mask[$new['line']])) {
$feedback_mask[$ii] = true;
}
}
/*
$handle_ids = mpull($this->comments, 'getUserPHID');
$handles = array();
$handle_data = new ToolsHandleData($handle_ids, $handles);
$handle_data->needNames();
prep($handle_data);
$this->comments = msort($this->comments, 'getID');
foreach ($this->comments as $comment) {
if ($this->isCommentInNewFile($comment)) {
$new_comments[$comment->getFinalLine()][] = $comment;
} else {
$old_comments[$comment->getFinalLine()][] = $comment;
}
}
*/
}
$html = $this->renderTextChange(
$range_start,
$range_len,
$mask_force,
$feedback_mask,
$viewer_context,
$handles,
$old_comments,
$new_comments);
return $this->renderChangesetTable($this->changeset, $html);
}
private function isCommentInNewFile(DifferentialInlineComment $comment) {
if ($this->oldChangesetID) {
return ($comment->getChangesetID() != $this->oldChangesetID);
} else {
return $comment->getIsNewFile();
}
}
protected function renderShield($message, $more) {
$end = $this->getLength();
$changeset_id = $this->getChangesetID();
if ($more) {
$more =
' '.
phutil_render_tag(
'a',
array(
'mustcapture' => true,
'sigil' => 'show-more',
'class' => 'complete',
'meta' => 'TODO',
),
'Show File Contents');
} else {
$more = null;
}
return phutil_render_tag(
'tr',
array(
'sigil' => 'contex-target',
),
'<td class="differential-shield" colspan="4">'.
phutil_escape_html($message).
$more.
'</td>');
}
protected function renderTextChange(
$range_start,
$range_len,
$mask_force,
$feedback_mask,
$viewer_context,
$handles,
array $old_comments,
array $new_comments) {
$context_not_available = null;
if ($this->missingOld || $this->missingNew) {
$context_not_available = phutil_render_tag(
'tr',
array(
'sigil' => 'context-target',
),
'<td colspan="4" class="show-more">'.
'Context not available.'.
'</td>');
$context_not_available = $context_not_available;
}
$html = array();
$rows = max(
count($this->old),
count($this->new));
if ($range_start === null) {
$range_start = 0;
}
if ($range_len === null) {
$range_len = $rows;
}
$range_len = min($range_len, $rows - $range_start);
$gaps = array();
$gap_start = 0;
$in_gap = false;
$mask = $this->visible + $mask_force + $feedback_mask;
$mask[$range_start + $range_len] = true;
for ($ii = $range_start; $ii <= $range_start + $range_len; $ii++) {
if (isset($mask[$ii])) {
if ($in_gap) {
$gap_length = $ii - $gap_start;
if ($gap_length <= self::LINES_CONTEXT) {
for ($jj = $gap_start; $jj <= $gap_start + $gap_length; $jj++) {
$mask[$jj] = true;
}
} else {
$gaps[] = array($gap_start, $gap_length);
}
$in_gap = false;
}
} else {
if (!$in_gap) {
$gap_start = $ii;
$in_gap = true;
}
}
}
$gaps = array_reverse($gaps);
$changeset = $this->changesetID;
for ($ii = $range_start; $ii < $range_start + $range_len; $ii++) {
if (empty($mask[$ii])) {
$gap = array_pop($gaps);
$top = $gap[0];
$len = $gap[1];
$end = $top + $len - 20;
$contents = array();
if ($len > 40) {
$contents[] = phutil_render_tag(
'a',
array(
'href' => '#',
'mustcapture' => true,
'sigil' => 'show-more',
'meta' => '', // TODO
),
"\xE2\x96\xB2 Show 20 Lines");
}
$contents[] = phutil_render_tag(
'a',
array(
'href' => '#',
'mustcapture' => true,
'sigil' => 'show-more',
'meta' => '', // TODO
),
'Show All '.$len.' Lines');
if ($len > 40) {
$contents[] = phutil_render_tag(
'a',
array(
'href' => '#',
'mustcapture' => true,
'sigil' => 'show-more',
'meta' => '', // TODO
),
"\xE2\x96\xBC Show 20 Lines");
};
$container = phutil_render_tag(
'tr',
array(
'sigil' => 'context-target',
),
'<td colspan="4" class="show-more">'.
implode(' &bull; ', $contents).
'</td>');
$html[] = $container;
$ii += ($len - 1);
continue;
}
if (isset($this->old[$ii])) {
$o_num = $this->old[$ii]['line'];
$o_text = $this->oldRender[$ii];
$o_attr = null;
if ($this->old[$ii]['type']) {
if (empty($this->new[$ii])) {
$o_attr = ' class="old old-full"';
} else {
$o_attr = ' class="old"';
}
}
} else {
$o_num = null;
$o_text = null;
$o_attr = null;
}
if (isset($this->new[$ii])) {
$n_num = $this->new[$ii]['line'];
$n_text = $this->newRender[$ii];
$n_attr = null;
if ($this->new[$ii]['type']) {
if (empty($this->old[$ii])) {
$n_attr = ' class="new new-full"';
} else {
$n_attr = ' class="new"';
}
}
} else {
$n_num = null;
$n_text = null;
$n_attr = null;
}
if (($o_num && !empty($this->missingOld[$o_num])) ||
($n_num && !empty($this->missingNew[$n_num]))) {
$html[] = $context_not_available;
}
if ($o_num) {
$o_id = ' id="C'.$changeset.'OL'.$o_num.'"';
} else {
$o_id = null;
}
if ($n_num) {
$n_id = ' id="C'.$changeset.'NL'.$n_num.'"';
} else {
$n_id = null;
}
// NOTE: The Javascript is sensitive to whitespace changes in this
// block!
$html[] =
'<tr>'.
'<th'.$o_id.'>'.$o_num.'</th>'.
'<td'.$o_attr.'>'.$o_text.'</td>'.
'<th'.$n_id.'>'.$n_num.'</th>'.
'<td'.$n_attr.'>'.$n_text.'</td>'.
'</tr>';
if ($context_not_available && ($ii == $rows - 1)) {
$html[] = $context_not_available;
}
if ($o_num && isset($old_comments[$o_num])) {
foreach ($old_comments[$o_num] as $comment) {
$xhp = $this->renderInlineComment(
$comment,
$viewer_context,
$handles);
$html[] =
'<tr class="inline"><th /><td>'.
$xhp.
'</td><th /><td /></tr>';
}
}
if ($n_num && isset($new_comments[$n_num])) {
foreach ($new_comments[$n_num] as $comment) {
$xhp = $this->renderInlineComment(
$comment,
$viewer_context,
$handles);
$html[] =
'<tr class="inline"><th /><td /><th /><td>'.
$xhp.
'</td></tr>';
}
}
}
return implode('', $html);
}
private function renderInlineComment(
DifferentialInlineComment $comment,
$viewer_context,
$handles) {
$edit = $viewer_context &&
($comment->getUserPHID() == $viewer_context->getUserID()) &&
(!$comment->getFeedbackID());
$is_new = $this->isCommentInNewFile($comment);
return '';
/*
return <differential:inline-comment
inline={$comment}
edit={$edit}
isnew={$is_new}
handle={$handles[$comment->getUserPHID()]} />;
*/
}
protected function renderPropertyChangeHeader($changeset) {
$old = $changeset->getOldProperties();
$new = $changeset->getNewProperties();
if ($old === $new) {
return null;
}
if ($changeset->getChangeType() == DifferentialChangeType::TYPE_ADD &&
$new == array('unix:filemode' => '100644')) {
return null;
}
if ($changeset->getChangeType() == DifferentialChangeType::TYPE_DELETE &&
$old == array('unix:filemode' => '100644')) {
return null;
}
return null;
/*
$table = <table class="differential-property-table" />;
$table->appendChild(
<tr class="property-table-header">
<th>Property Changes</th>
<td class="oval">Old Value</td>
<td class="nval">New Value</td>
</tr>);
$keys = array_keys($old + $new);
sort($keys);
foreach ($keys as $key) {
$oval = idx($old, $key);
$nval = idx($new, $key);
if ($oval !== $nval) {
if ($oval === null) {
$oval = <em>null</em>;
}
if ($nval === null) {
$nval = <em>null</em>;
}
$table->appendChild(
<tr>
<th>{$key}</th>
<td class="oval">{$oval}</td>
<td class="nval">{$nval}</td>
</tr>);
}
}
return $table;
*/
}
protected function renderChangesetTable($changeset, $contents) {
$props = $this->renderPropertyChangeHeader($this->changeset);
$table = null;
if ($contents) {
$table =
- '<table class="differential-diff">'.
+ '<table class="differential-diff remarkup-code">'.
$contents.
'</table>';
}
if (!$table && !$props) {
$notice = $this->renderChangeTypeHeader($this->changeset, true);
} else {
$notice = $this->renderChangeTypeHeader($this->changeset, false);
}
return implode(
"\n",
array(
$notice,
$props,
$table,
));
}
protected function renderChangeTypeHeader($changeset, $force) {
static $articles = array(
DifferentialChangeType::FILE_IMAGE => 'an',
);
static $files = array(
DifferentialChangeType::FILE_TEXT => 'file',
DifferentialChangeType::FILE_IMAGE => 'image',
DifferentialChangeType::FILE_DIRECTORY => 'directory',
DifferentialChangeType::FILE_BINARY => 'binary file',
DifferentialChangeType::FILE_SYMLINK => 'symlink',
);
static $changes = array(
DifferentialChangeType::TYPE_ADD => 'added',
DifferentialChangeType::TYPE_CHANGE => 'changed',
DifferentialChangeType::TYPE_DELETE => 'deleted',
DifferentialChangeType::TYPE_MOVE_HERE => 'moved from',
DifferentialChangeType::TYPE_COPY_HERE => 'copied from',
DifferentialChangeType::TYPE_MOVE_AWAY => 'moved to',
DifferentialChangeType::TYPE_COPY_AWAY => 'copied to',
DifferentialChangeType::TYPE_MULTICOPY
=> 'deleted after being copied to',
);
$change = $changeset->getChangeType();
$file = $changeset->getFileType();
$message = null;
if ($change == DifferentialChangeType::TYPE_CHANGE &&
$file == DifferentialChangeType::FILE_TEXT) {
if ($force) {
// We have to force something to render because there were no changes
// of other kinds.
$message = "This {$files[$file]} was not modified.";
} else {
// Default case of changes to a text file, no metadata.
return null;
}
} else {
$verb = idx($changes, $change, 'changed');
switch ($change) {
default:
$message = "This {$files[$file]} was <strong>{$verb}</strong>.";
break;
case DifferentialChangeType::TYPE_MOVE_HERE:
case DifferentialChangeType::TYPE_COPY_HERE:
$message =
"This {$files[$file]} was {$verb} ".
"<strong>{$changeset->getOldFile()}</strong>.";
break;
case DifferentialChangeType::TYPE_MOVE_AWAY:
case DifferentialChangeType::TYPE_COPY_AWAY:
case DifferentialChangeType::TYPE_MULTICOPY:
$paths = $changeset->getAwayPaths();
if (count($paths) > 1) {
$message =
"This {$files[$file]} was {$verb}: ".
"<strong>".implode(', ', $paths)."</strong>.";
} else {
$message =
"This {$files[$file]} was {$verb} ".
"<strong>".reset($paths)."</strong>.";
}
break;
case DifferentialChangeType::TYPE_CHANGE:
$message = "This is ".idx($articles, $file, 'a')." {$files[$file]}.";
break;
}
}
return
'<div class="differential-meta-notice">'.
$message.
'</div>';
}
public function renderForEmail() {
$ret = '';
$min = min(count($this->old), count($this->new));
for ($i = 0; $i < $min; $i++) {
$o = $this->old[$i];
$n = $this->new[$i];
if (!isset($this->visible[$i])) {
continue;
}
if ($o['line'] && $n['line']) {
// It is quite possible there are better ways to achieve this. For
// example, "white-space: pre;" can do a better job, WERE IT NOT for
// broken email clients like OWA which use newlines to do weird
// wrapping. So dont give them newlines.
if (isset($this->intra[$i])) {
$ret .= sprintf(
"<font color=\"red\">-&nbsp;%s</font><br/>",
str_replace(" ", "&nbsp;", phutil_escape_html($o['text']))
);
$ret .= sprintf(
"<font color=\"green\">+&nbsp;%s</font><br/>",
str_replace(" ", "&nbsp;", phutil_escape_html($n['text']))
);
} else {
$ret .= sprintf("&nbsp;&nbsp;%s<br/>",
str_replace(" ", "&nbsp;", phutil_escape_html($n['text']))
);
}
} else if ($o['line'] && !$n['line']) {
$ret .= sprintf(
"<font color=\"red\">-&nbsp;%s</font><br/>",
str_replace(" ", "&nbsp;", phutil_escape_html($o['text']))
);
} else {
$ret .= sprintf(
"<font color=\"green\">+&nbsp;%s</font><br/>",
str_replace(" ", "&nbsp;", phutil_escape_html($n['text']))
);
}
}
return $ret;
}
}
diff --git a/src/view/page/standard/PhabricatorStandardPageView.php b/src/view/page/standard/PhabricatorStandardPageView.php
index a0679d92fc..d5376d2fa6 100755
--- a/src/view/page/standard/PhabricatorStandardPageView.php
+++ b/src/view/page/standard/PhabricatorStandardPageView.php
@@ -1,110 +1,111 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorStandardPageView extends AphrontPageView {
private $baseURI;
private $applicationName;
private $tabs = array();
private $selectedTab;
private $glyph;
public function setApplicationName($application_name) {
$this->applicationName = $application_name;
return $this;
}
public function getApplicationName() {
return $this->applicationName;
}
public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function getBaseURI() {
return $this->baseURI;
}
public function setTabs(array $tabs, $selected_tab) {
$this->tabs = $tabs;
$this->selectedTab = $selected_tab;
return $this;
}
public function getTitle() {
return $this->getGlyph().' '.parent::getTitle();
}
protected function getHead() {
return
- '<link rel="stylesheet" type="text/css" href="/rsrc/css/base.css" />';
+ '<link rel="stylesheet" type="text/css" href="/rsrc/css/base.css" />'.
+ '<link rel="stylesheet" type="text/css" href="/rsrc/css/syntax.css" />';
}
public function setGlyph($glyph) {
$this->glyph = $glyph;
return $this;
}
public function getGlyph() {
return $this->glyph;
}
protected function getBody() {
$tabs = array();
foreach ($this->tabs as $name => $tab) {
$tabs[] = phutil_render_tag(
'a',
array(
'href' => idx($tab, 'href'),
'class' => ($name == $this->selectedTab)
? 'aphront-selected-tab'
: null,
),
phutil_escape_html(idx($tab, 'name')));
}
$tabs = implode('', $tabs);
if ($tabs) {
$tabs = '<span class="aphront-head-tabs">'.$tabs.'</span>';
}
return
'<div class="aphront-standard-page">'.
'<div class="aphront-standard-header">'.
'<a href="/">Phabricator</a> '.
phutil_render_tag(
'a',
array(
'href' => $this->getBaseURI(),
'class' => 'aphront-head-appname',
),
phutil_escape_html($this->getApplicationName())).
$tabs.
'</div>'.
$this->renderChildren().
'<div style="clear: both;"></div>'.
'</div>';
}
protected function getTail() {
return '';
}
}
diff --git a/webroot/rsrc/css/base.css b/webroot/rsrc/css/base.css
index dbbe105740..dedfd4699e 100644
--- a/webroot/rsrc/css/base.css
+++ b/webroot/rsrc/css/base.css
@@ -1,749 +1,760 @@
html {
overflow-y: scroll;
}
body, div, dl, dt, dd, ul, ol, li,
h1, h2, h3, h4, h5, h6,
pre, form, fieldset,
p, blockquote, th, td, button {
margin: 0;
padding: 0;
outline: 0;
border: 0;
}
html {
padding-bottom: 16em;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
fieldset, img {
border: 0;
}
address, caption, cite, code, dfn, th, var {
font-style: normal;
font-weight: normal;
}
ol, ul {
list-style: none;
}
caption, th {
text-align: left;
}
td, th {
vertical-align: top;
}
h1, h2, h3, h4, h5, h6 {
font-size: 100%;
font-weight: bold;
}
body {
font: 13px/1.231 'lucida grande', tahoma, verdana, arial, sans-serif;
background: #ACACAC;
direction: ltr;
text-align: left;
unicode-bidi: embed;
*font-size: small;
}
select, input, button, textarea, button {
font: 99% 'lucida grande', tahoma, verdana, arial, clean, sans-serif;
}
table {
font-size: inherit;
font: 100%;
}
h1 {
font-size: 16px;
}
h2 {
font-size: 14px;
}
a {
-moz-outline-style: none;
text-decoration: none;
cursor: pointer;
}
a:visited {
color: #3b5998;
}
a:link {
color: #3b5998;
}
a:hover {
text-decoration: underline;
}
img {
display: block;
}
/******************************************************************************/
/* Buttons */
/******************************************************************************/
button,
a.button,
a.button:visited,
input.inputsubmit {
background: #5e77aa url('/rsrc/image/sprite.png') 0 0 repeat-x;
border: 1px solid #29447e;
border-bottom-color: #1a356e;
color: #fff;
cursor: pointer;
font-weight: bold;
text-align: center;
white-space: nowrap;
display: inline-block;
font-size: 13px;
overflow: visible;
padding: 2px 8px 3px 8px;
line-height: 18px;
vertical-align: baseline;
width: auto;
box-shadow: 0px 1px 0px rgba(0,0,0,.12);
-moz-box-shadow: 0px 1px 0px rgba(0,0,0,.12);
-webkit-box-shadow: 0px 1px 0px rgba(0,0,0,.12);
}
button {
*padding: 2px 4px 1px 8px;
_padding-right: 6px;
}
a.button,
a.button:visited {
*padding: 3px 8px 4px;
}
/* Buttons with images (full size only) */
button.icon,
a.icon,
a.icon:visited {
padding-left: 0;
position: relative;
text-indent: 29px;
}
/* Fix for IE7 within table cells ? */
td button {
*width: 100%;
*padding-right: 8px;
}
button:active,
a.button:active {
background-color: #4f6aa3;
background-position: 0 -100px;
border-bottom-color: #29447e;
}
button.green,
a.green,
a.green:visited {
background-color: #6da952;
background-position: 0 -50px;
border: 1px solid #3b6e22;
border-bottom-color: #2c5a15;
}
button.green:active,
a.green:active {
background-color: #5e9d43;
background-position: 0 -150px;
border-bottom-color: #3b6e22;
}
button.grey,
input.inputaux,
a.grey,
a.grey:visited,
a.button.disabled,
button.disabled {
background-color: #e4e5e5;
background-position: 0 -250px;
border: 1px solid #999;
border-bottom-color: #888;
color: #333;
box-shadow: 0px 1px 0px rgba(0,0,0,.07);
-moz-box-shadow: 0px 1px 0px rgba(0,0,0,.07);
-webkit-box-shadow: 0px 1px 0px rgba(0,0,0,.07);
}
a.disabled,
button.disabled {
filter:alpha(opacity=50);
-moz-opacity:0.5;
-khtml-opacity: 0.5;
opacity: 0.5;
}
button.grey:active,
a.grey:active,
button.grey_active {
background-color: #dddddd;
background-position: 0 -200px;
border-bottom-color: #999;
}
button:active::-moz-focus-inner,
button:focus::-moz-focus-inner {
border-color: #405071;
}
button.green:active::-moz-focus-inner,
button.green:focus::-moz-focus-inner {
border-color: #4c713b;
}
button.grey:active::-moz-focus-inner,
button.grey:focus::-moz-focus-inner {
border-color: #666;
}
a.button:hover {
text-decoration: none;
}
button.small,
a.small,
a.small:visited {
padding: 2px 7px;
height: auto;
font-size: 11px;
line-height: 16px;
}
/******************************************************************************/
/* Aphront */
/******************************************************************************/
.aphront-standard-page {
background: #ffffff;
border-bottom: 1px solid #888888;
font-size: 14px;
-webkit-box-shadow: 0 0 6px #000;
-mox-box-shadow: 0 0 6px #000;
box-shadow: 0 0 6px #000;
}
.aphront-standard-header {
background: #003366;
color: white;
padding: 1em 1em 0.5em 1em;
overflow: hidden;
position: relative;
}
.aphront-standard-header a {
color: white;
}
.aphront-standard-header .aphront-head-tabs {
padding: 0 1em;
font-size: 13px;
font-weight: bold;
}
.aphront-standard-header .aphront-head-tabs a {
border-bottom: 3px solid transparent;
padding: 0.5em 0.75em;
position: relative;
bottom: 2px;
}
.aphront-standard-header .aphront-head-tabs a.aphront-selected-tab {
border-bottom-color: #cccccc;
}
.aphront-standard-header .aphront-head-appname {
padding: 0 1em;
text-transform: uppercase;
}
.aphront-directory-list {
margin: 1em 3% 8em;
}
.aphront-directory-category h1 {
border-bottom: 1px solid #cccccc;
margin-bottom: .5em;
padding-bottom: .1em;
}
.aphront-directory-list h2 {
font-size: 14px;
font-weight: bold;
padding: 0;
margin: 0;
}
.aphront-directory-list p {
color: #444444;
font-size: 12px;
padding: .05em .5em .5em;
}
.aphront-directory-category {
padding: 10px;
width: 300px;
float: left;
}
.aphront-directory-group {
padding: 0 .5em 3em;
}
.aphront-panel-view {
background: #f3f3f3;
border: 1px solid #c0c0c0;
border-width: 1px 0 0;
padding: 1em 2em;
margin: 1em 2em;
}
.aphront-panel-view h1 {
font-size: 14px;
font-weight: bold;
padding: 2px 0 8px;
}
.aphront-panel-view a.create-button {
float: right;
}
.aphront-panel-width-form {
width: 720px;
margin-right: auto;
margin-left: auto;
}
.aphront-panel-width-wide {
width: 1080px;
margin-right: auto;
margin-left: auto;
}
.aphront-table-view {
width: 100%;
border-collapse: collapse;
background: #fdfdfd;
border: 1px solid #003366;
}
.aphront-table-view tr.alt {
background: #efefef;
}
.aphront-table-view th {
font-size: 12px;
font-weight: bold;
padding: 4px 8px;
background: #003366;
color: white;
white-space: nowrap;
}
.aphront-table-view td.header {
padding: 4px 8px;
background: #3b5998;
color: white;
white-space: nowrap;
text-align: right;
}
.aphront-table-view td {
vertical-align: top;
padding: 4px 8px;
font-size: 11px;
white-space: nowrap;
}
.aphront-table-view td.action {
padding-top: 1px;
padding-bottom: 1px;
}
.aphront-table-view td.larger {
font-size: 14px;
}
.aphront-table-view td.pri {
font-weight: bold;
}
.aphront-table-view td.wide {
white-space: normal;
width: 100%;
}
.aphront-table-view td.right {
text-align: right;
}
.aphront-table-view td.mono {
font-family: "Monaco", monospace;
font-size: 10px;
}
.aphront-table-view tr.no-data td {
padding: 1em;
text-align: center;
color: #888888;
font-style: italic;
}
/******************************************************************************/
/* forms */
/******************************************************************************/
.aphront-form-view {
background: #e7e7e7;
border: 1px solid #c4c4c4;
padding: 1em;
}
.aphront-form-view label {
padding-top: 4px;
width: 14%;
float: left;
text-align: right;
font-weight: bold;
font-size: 13px;
color: #666666;
}
.aphront-form-input {
margin-left: 15%;
margin-right: 25%;
width: 60%;
}
.aphront-form-error {
width: 23%;
float: right;
color: #aa0000;
font-weight: bold;
padding-top: 4px;
}
.aphront-form-input input,
.aphront-form-input textarea {
font-size: 12px;
width: 100%;
}
.aphront-form-input textarea {
height: 12em;
}
.aphront-form-control {
padding: 4px;
}
.aphront-form-control-submit button,
.aphront-form-control-submit a.button {
float: right;
margin: 1em 0 0em 2%;
}
.aphront-form-view .aphront-form-caption {
font-size: 11px;
color: #444444;
text-align: right;
clear: both;
margin-right: 25%;
margin-left: 15%;
}
.aphront-error-view {
width: 720px;
margin: 1em auto;
border: 1px solid #aa0000;
padding: 1em;
background: #f9b9bc;
}
.aphront-form-instructions {
margin: 2em 3%;
}
.aphront-form-control-static .aphront-form-input {
padding-top: 4px;
font-size: 13px;
}
/******************************************************************************/
/* dialog */
/******************************************************************************/
.aphront-dialog-view {
width: 480px;
padding: 8px;
background: #666;
margin: auto;
}
.aphront-dialog-head {
background: #003366;
border: none;
font-size: 15px;
padding: 5px 12px 6px;
color: #ffffff;
}
.aphront-dialog-body {
background: #ffffff;
padding: 16px 12px;
border: none;
overflow: hidden;
}
.aphront-dialog-tail {
border: none;
background: #ededed;
padding: 0.5em;
text-align: right;
}
.aphront-dialog-tail button,
.aphront-dialog-tail a.button {
float: right;
margin-left: .5em;
}
/******************************************************************************/
/* side nav */
/******************************************************************************/
table.aphront-side-nav-view {
width: 100%;
}
td.aphront-side-nav-content {
width: 100%;
}
th.aphront-side-nav-navigation {
border-right: 1px solid #bbbbbb;
}
th.aphront-side-nav-navigation a {
display: block;
margin: 0 0 2px;
min-width: 150px;
padding: 3px 8px 3px 24px;
font-weight: bold;
white-space: nowrap;
text-decoration: none;
}
th.aphront-side-nav-navigation a:hover {
text-decoration: none;
background: #f3f3f9;
}
th.aphront-side-nav-navigation hr {
height: 1px;
background: #eeeeee;
border: 0px;
margin: 12px 0px;
}
th.aphront-side-nav-navigation a.aphront-side-nav-selected,
th.aphront-side-nav-navigation a.aphront-side-nav-selected:hover {
background: #d8dfea;
}
/******************************************************************************/
/* differential toc */
/******************************************************************************/
.differential-toc {
margin: 25px 0;
max-width: 1118px;
border: 1px solid #666622;
background: #efefdf;
padding: 15px 20px;
font-size: 13px;
}
.differential-toc-meta {
color: #666666;
padding-left: 1em;
}
.differential-toc-char,
.differential-toc-prop {
width: 1.25em;
text-align: center;
font-weight: bold;
}
.differential-toc-ftype {
padding: 0 .5em;
text-align: center;
color: #666666;
}
.differential-toc-file {
color: #444444;
}
.differential-toc h1 {
border-bottom: 1px solid #aaaa99;
padding-bottom: 8px;
margin-bottom: 8px;
}
/******************************************************************************/
/* changeset view */
/******************************************************************************/
.differential-diff {
background: #ffffff;
font-family: "Menlo", "Consolas", "Monaco", monospace;
font-size: 10px;
width: 100%;
}
.differential-diff td {
/* using monospace fonts makes ex/em most useful:
*
* Unfortunately, firefox 3.6 renders diffs columns for added and removed
* files "way-too-wide" when given em as the dimension measurement, so we
* use an eyeballed ex equivalent and reset it to the ch character width
* measurement for browsers that support that css3 measurement.
*/
width: 88ex;
width: 81ch;
/*
Disable ligatures in Firefox. Firefox 3 has fancypants ligature support, but
it gets applied to monospaced fonts, which sucks because it means that the
"fi" ligature only takes up one character, e.g. It's probably the font's
fault that it even specifies ligatures (seriously, what the hell?) but
that's hard to fix and this is "easy" to "fix": custom letter spacing
disables ligatures, as long as it's at least 0.008333-repeating pixels of
custom letter spacing. I have no idea where this number comes from, but note
that .83333.. = 5/6. -epriestley
*/
letter-spacing: 0.0083334px;
vertical-align: top;
white-space: pre;
padding: 0 8px 1px;
line-height: 16px;
overflow: hidden;
}
.differential-diff th {
text-align: right;
padding: 2px 6px;
width: 44px;
vertical-align: top;
background: #eeeeee;
color: #888888;
cursor: pointer;
border-style: solid;
border-width: 0px 1px;
border-color: #eeeeee #999999 #eeeeee #dddddd;
font-weight: bold;
font-family: "Verdana";
font-size: 11px;
overflow: hidden;
}
.differential-diff td.old {
background: #ffd0d0;
color: #161111;
}
.differential-diff td.new {
background: #d0ffd0;
color: #111611;
}
.differential-diff td.old-full,
.differential-diff td.old span.bright {
background: #ffaaaa;
color: #221111;
}
.differential-diff td.new-full,
.differential-diff td.new span.bright {
background: #aaffaa;
color: #112211;
}
.differential-diff td.show-more,
.differential-diff td.differential-shield {
background: #ffffee;
padding: 1em;
text-align: center;
font-family: "Verdana";
font-size: 11px;
border: 1px solid #ccccaa;
white-space: normal;
}
.differential-diff td.show-more {
color: #999966;
}
.differential-diff td.differential-shield {
text-align: center;
max-width: 1160px;
}
.differential-diff td.differential-shield a {
font-weight: bold;
}
.differential-primary-pane {
margin: 0 40px;
max-width: 1162px;
}
+
+/************* meta notice ************************************************ */
+
+.differential-meta-notice {
+ border: 1px solid #ffdd99;
+ background: #ffeeaa;
+ font-family: "Verdana";
+ font-size: 11px;
+ padding: 1em;
+ margin: 0 0 6px 0;
+}
diff --git a/webroot/rsrc/css/syntax.css b/webroot/rsrc/css/syntax.css
new file mode 100644
index 0000000000..706a864d0f
--- /dev/null
+++ b/webroot/rsrc/css/syntax.css
@@ -0,0 +1,119 @@
+.remarkup-code .uu { /* Forbidden Unicode */
+ color: #aa0066;
+}
+
+.remarkup-code .over-the-line {
+ color: #aa0066;
+ margin-right: 1px;
+}
+
+.remarkup-code td span {
+ padding: 1px 0 3px;
+}
+
+
+.remarkup-code .hll {
+ background-color: #ffffcc;
+}
+
+.remarkup-code .c, /* Comment */
+.remarkup-code .cm, /* Comment.Multiline */
+.remarkup-code .c1, /* Comment.Single */
+.remarkup-code .cs { /* Comment.Special */
+ color: #666666;
+}
+
+.remarkup-code .sd, /* Literal.String.Doc */
+.remarkup-code .sh { /* Literal.String.Heredoc */
+ color: #000000;
+}
+
+.remarkup-code .s, /* Literal.String */
+.remarkup-code .sb, /* Literal.String.Backtick */
+.remarkup-code .sc, /* Literal.String.Char */
+.remarkup-code .s2, /* Literal.String.Double */
+.remarkup-code .s1, /* Literal.String.Single */
+.remarkup-code .sx { /* Literal.String.Other */
+ color: #766510;
+}
+
+.remarkup-code .sr { /* Literal.String.Regex */
+ color: #BB6688;
+}
+
+.remarkup-code .nv, /* Name.Variable */
+.remarkup-code .vi, /* Name.Variable.Instance */
+.remarkup-code .vg { /* Name.Variable.Global */
+ color: #001294;
+}
+
+.remarkup-code .na { /* Name.Attribute */
+ color: #354BB3;
+}
+
+.remarkup-code .kc, /* Keyword.Constant */
+.remarkup-code .no { /* Name.Constant */
+ color: #000A65;
+}
+
+.remarkup-code .k, /* Keyword */
+.remarkup-code .kd, /* Keyword.Declaration */
+.remarkup-code .kn, /* Keyword.Namespace */
+.remarkup-code .kt { /* Keyword.Type */
+ color: #AA4000;
+}
+
+.remarkup-code .cp, /* Comment.Preproc */
+.remarkup-code .kp, /* Keyword.Pseudo */
+.remarkup-code .kr, /* Keyword.Reserved */
+.remarkup-code .nb, /* Name.Builtin */
+.remarkup-code .bp { /* Name.Builtin.Pseudo */
+ color: #304A96;
+}
+
+.remarkup-code .nc, /* Name.Class */
+.remarkup-code .nt, /* Name.Tag */
+.remarkup-code .vc { /* Name.Variable.Class */
+ color: #00702A;
+}
+
+.remarkup-code .nf, /* Name.Function */
+.remarkup-code .nx { /* Name.Other */
+ color: #004012;
+}
+
+.remarkup-code .o, /* Operator */
+.remarkup-code .ss { /* Literal.String.Symbol */
+ color: #AA2211;
+}
+
+.remarkup-code .m, /* Literal.Number */
+.remarkup-code .mf, /* Literal.Number.Float */
+.remarkup-code .mh, /* Literal.Number.Hex */
+.remarkup-code .mi, /* Literal.Number.Integer */
+.remarkup-code .mo, /* Literal.Number.Oct */
+.remarkup-code .il { /* Literal.Number.Integer.Long */
+ color: #601200;
+}
+
+.remarkup-code .gd { color: #A00000 } /* Generic.Deleted */
+.remarkup-code .ge { } /* Generic.Emph */
+.remarkup-code .gr { color: #FF0000 } /* Generic.Error */
+.remarkup-code .gh { color: #000080; } /* Generic.Heading */
+.remarkup-code .gi { color: #00A000 } /* Generic.Inserted */
+.remarkup-code .go { color: #808080 } /* Generic.Output */
+.remarkup-code .gp { color: #000080 } /* Generic.Prompt */
+.remarkup-code .gs { } /* Generic.Strong */
+.remarkup-code .gu { color: #800080 } /* Generic.Subheading */
+.remarkup-code .gt { color: #0040D0 } /* Generic.Traceback */
+.remarkup-code .nd { color: #AA22FF } /* Name.Decorator */
+.remarkup-code .ni { color: #999999 } /* Name.Entity */
+.remarkup-code .ne { color: #D2413A } /* Name.Exception */
+.remarkup-code .nl { color: #A0A000 } /* Name.Label */
+.remarkup-code .nn { color: #0000FF } /* Name.Namespace */
+.remarkup-code .ow { color: #AA22FF } /* Operator.Word */
+.remarkup-code .w { color: #bbbbbb } /* Text.Whitespace */
+.remarkup-code .se { color: #BB6622 } /* Literal.String.Escape */
+.remarkup-code .si { color: #BB6688 } /* Literal.String.Interpol */
+
+

File Metadata

Mime Type
text/x-diff
Expires
Tue, Mar 17, 12:43 AM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
963088
Default Alt Text
(59 KB)

Event Timeline