将.patch转换为带有样式的html输出,以便在线查看

时间:2014-09-02 10:33:23

标签: php

所以我有一个工具,用户可以在其中上传他们的SVN .patch文件。而不是单独下载和查看它我希望它是否可以直接在线查看红绿色样式。

补丁文件[/uploads/Bug123.patch]

### Eclipse Workspace Patch 1.0
Index: src/main/java/com/admin/Screen.java
===================================================================
--- src/main/java/com/admin/Screen.java (revision 2)
+++ src/main/java/com/admin/Screen.java (working copy)
@@ -147,20 +147,22 @@
-       System.out.println("Hello World"); 
+       System.out.println("Hello New World"); 

可见[/viewer.php?file=Bug123.patch]

<html><style>.red {background:lightcoral} .green {background:greenyellow} .yellow {background:yellow; font-weight:bold}</style><pre>
### Eclipse Workspace Patch 1.0
Index: src/main/java/com/admin/Screen.java
===================================================================
<span class="yellow">--- src/main/java/com/admin/Screen.java    (revision 2)</span>
<span class="yellow">+++ src/main/java/com/admin/Screen.java    (working copy)</span>
@@ -147,20 +147,22 @@
<span class="red">-     System.out.println("Hello World"); </span>
<span class="green">+       System.out.println("Hello New World"); </span>
</pre></html>

1 个答案:

答案 0 :(得分:1)

您可以尝试以下方式:

<?php

$file = __DIR__ . '/foo.patch';

echo '<doctype html>
<html>
<head>
<style>
.header {
   color: black;
}
.header-comment {
   color: grey;
}
.file-input, .file-change {
   color: green;
}
.file-output {
   color: blue;
}
.file-line-nos {
   color: blue;
}
.line-context {
   color: darkgrey;
}
.line-add {
   color: green;
}
.line-change {
   color: yellow;
}
.line-del {
   color: red;
}
</style>
</head>
<body>
';


echo PatchParser::file_to_html($file);

echo '</body></html>';

class PatchParser {
   const MODE_HEADER = 1;
   const MODE_FILE = 2;

   const LINE_TYPE_HEADER       = 0x0001;
   const LINE_TYPE_COMMENT      = 0x0002;
   const LINE_TYPE_FILE_IN      = 0x1001;
   const LINE_TYPE_FILE_OUT     = 0x1002;
   const LINE_TYPE_FILE_CHANGE  = 0x1003;
   const LINE_TYPE_LINE_NUMBERS = 0x1004;
   const LINE_TYPE_CONTEXT      = 0x2001;
   const LINE_TYPE_ADDITION     = 0x2002;
   const LINE_TYPE_DELETION     = 0x2003;
   const LINE_TYPE_CHANGE       = 0x2004;

   const MARKER_IN_FILE               = '+++';
   const MARKER_CHANGED_FILE          = '***'; // Used for context diffs
   const MARKER_OUT_FILE              = '---';
   const MARKER_FILE_LINE_NUMBERS     = '@';
   const MARKER_HEADER_COMMENT        = '#';
   const MARKER_FILE_CHANGE           = '!';
   const MARKER_FILE_NORMAL_ADDITION  = '>';
   const MARKER_FILE_NORMAL_DELETION  = '<';
   const MARKER_FILE_UNIFIED_ADDITION = '+';
   const MARKER_FILE_UNIFIED_DELETION = '-';


   static public function file_to_html($file){
      return self::text_to_html(file_get_contents($file));
   }

   static public function text_to_html($contents){
      $parsed_lines = self::parse($contents);

      $classes = array(
         self::LINE_TYPE_HEADER        => 'header header-text',
         self::LINE_TYPE_COMMENT       => 'header header-comment',
         self::LINE_TYPE_FILE_IN       => 'file file-input',
         self::LINE_TYPE_FILE_OUT      => 'file file-output',
         self::LINE_TYPE_FILE_CHANGE   => 'file file-change',
         self::LINE_TYPE_LINE_NUMBERS  => 'file file-line-nos',
         self::LINE_TYPE_CONTEXT       => 'line line-context',
         self::LINE_TYPE_ADDITION      => 'line line-add',
         self::LINE_TYPE_DELETION      => 'line line-del',
         self::LINE_TYPE_CHANGE        => 'line line-change'
      );

      $no_lines = count($parsed_lines);
      $lines_width = strlen("$no_lines");

      $output = '<pre>';
      foreach ($parsed_lines AS $line_no => $line){
         ++$line_no;
         $output .= str_pad($line_no, $lines_width, " ", STR_PAD_LEFT)
            . ' '
            . '<span class="'
            . $classes[$line[1]]
            . '">'
            . htmlspecialchars($line[0])
            . '</span><br />';
      }
      return $output . '</pre>';
   }

   static public function parse($contents) {
      $lines = explode("\n", $contents);
      $output = array();

      $mode = self::MODE_HEADER;// Stay's in header mode until we encounter a file handle
      foreach ($lines AS $line) {
         // trim the line to remove excess whitespace, then test the prefix
         $trimmed_line = trim($line);
         $first_three_chars = substr($trimmed_line,0,3);

         // The types that can occur in both modes are the file names/types
         if ($first_three_chars === self::MARKER_IN_FILE) {
            $output[] = array($line, self::LINE_TYPE_FILE_IN);
            $mode = self::MODE_FILE;
            continue;
         }

         if ($first_three_chars === self::MARKER_CHANGED_FILE) {
            $output[] = array($line, self::LINE_TYPE_FILE_CHANGE);
            $mode = self::MODE_FILE;
            continue;
         }

         if (substr($trimmed_line,0,3) === self::MARKER_OUT_FILE) {
            $output[] = array($line, self::LINE_TYPE_FILE_OUT);
            $mode = self::MODE_FILE;
            continue;
         }

         // Otherwise our mode is important:
         if ($mode === self::MODE_HEADER){
            // Header mode only supports header text and comments:
            if (substr($trimmed_line, 0, 1) === self::MARKER_HEADER_COMMENT) {
               $output[] = array($line, self::LINE_TYPE_COMMENT);
            } else {
               $output[] = array($line, self::LINE_TYPE_HEADER);
            }
            continue;
         } else {
            $first_char = substr($line, 0, 1);
            $type = self::LINE_TYPE_CONTEXT;
            switch ($first_char) {
               case self::MARKER_FILE_CHANGE:
                  $type = self::LINE_TYPE_CHANGE;
                  break;
               case self::MARKER_FILE_LINE_NUMBERS:
                  $type = self::LINE_TYPE_LINE_NUMBERS;
                  break;
               case self::MARKER_FILE_NORMAL_ADDITION:
               case self::MARKER_FILE_UNIFIED_ADDITION:
                  $type = self::LINE_TYPE_ADDITION;
                  break;
               case self::MARKER_FILE_NORMAL_DELETION:
               case self::MARKER_FILE_UNIFIED_DELETION:
                  $type = self::LINE_TYPE_DELETION;
                  break;
            }
            $output[] = array($line, $type);
         }
      }
      return $output;
   }
}

我刚刚发布的here的输出有一个JS小提琴。

让我知道你的想法。它的逻辑非常简单。