Index: trunk/extensions/CodeReview/backend/DiffHighlighter.php |
— | — | @@ -4,6 +4,9 @@ |
5 | 5 | * Highlight a SVN diff for easier readibility |
6 | 6 | */ |
7 | 7 | class CodeDiffHighlighter { |
| 8 | + private $left = 0; |
| 9 | + private $right = 0; |
| 10 | + private $chunk = 0; |
8 | 11 | |
9 | 12 | /** |
10 | 13 | * Main entry point. Given a diff text, highlight it |
— | — | @@ -26,11 +29,132 @@ |
27 | 30 | */ |
28 | 31 | function splitLines( $text ) { |
29 | 32 | return implode( "\n", |
30 | | - array_map( array( $this, 'colorLine' ), |
| 33 | + array_map( array( $this, 'parseLine' ), |
31 | 34 | explode( "\n", $text ) ) ); |
32 | 35 | } |
33 | 36 | |
34 | 37 | /** |
| 38 | + * Internal dispatcher to a handler depending on line |
| 39 | + * Handles lines beginning with '-' '+' '@' and ' ' |
| 40 | + * @param string $line Diff line to parse |
| 41 | + * @return string HTML table line (with <tr></tr>) |
| 42 | + */ |
| 43 | + function parseLine( $line ) { |
| 44 | + if( $line === '' ) { return ""; } // do not create bogus lines |
| 45 | + |
| 46 | + # Dispatch diff lines to the proper handler |
| 47 | + switch( substr( $line, 0, 1 ) ) { |
| 48 | + case '-': |
| 49 | + if( substr( $line, 0, 3 ) === '---' ) { |
| 50 | + return; |
| 51 | + } |
| 52 | + $r = $this->handleLineDeletion( $line ); |
| 53 | + break; |
| 54 | + case '+': |
| 55 | + if( substr( $line, 0, 3 ) === '+++' ) { |
| 56 | + return; |
| 57 | + } |
| 58 | + $r = $this->handleLineAddition( $line ); |
| 59 | + break; |
| 60 | + case '@': |
| 61 | + $r = $this->handleChunkDelimiter( $line ); |
| 62 | + break; |
| 63 | + case ' ': |
| 64 | + $r = $this->handleUnchanged( $line ); |
| 65 | + break; |
| 66 | + |
| 67 | + # Patch lines that will be skipped: |
| 68 | + case '=': |
| 69 | + return; |
| 70 | + |
| 71 | + # Remaining case should be the file name |
| 72 | + default: |
| 73 | + $r = $this->handleLineFile( $line ); |
| 74 | + } |
| 75 | + |
| 76 | + # Return HTML generated by one of the handler |
| 77 | + return $r; |
| 78 | + } |
| 79 | + |
| 80 | + function formatLine( $content, $class = null ) { |
| 81 | + $formatLN = |
| 82 | + "<td class=\"linenumbers\">%s</td>" |
| 83 | + . "<td class=\"linenumbers\">%s</td>" |
| 84 | + ; |
| 85 | + |
| 86 | + if( is_null($class) ) { |
| 87 | + return sprintf( "<tr>{$formatLN}<td>%s</td></tr>\n", |
| 88 | + $this->left, |
| 89 | + $this->right, |
| 90 | + $content |
| 91 | + ); |
| 92 | + } |
| 93 | + |
| 94 | + # Skip line number when they do not apply |
| 95 | + $left = $right = ' '; |
| 96 | + |
| 97 | + switch( $class ) { |
| 98 | + case 'chunkdelimiter': |
| 99 | + $left = $right = '—'; |
| 100 | + break; |
| 101 | + case 'unchanged': |
| 102 | + $left = $this->left; |
| 103 | + $right = $this->right; |
| 104 | + break; |
| 105 | + case 'del': |
| 106 | + $left = $this->left; |
| 107 | + break; |
| 108 | + case 'ins': |
| 109 | + $right = $this->right; |
| 110 | + break; |
| 111 | + |
| 112 | + default: |
| 113 | + # Rely on $left, $right initialization above |
| 114 | + } |
| 115 | + |
| 116 | + $classAttr = is_null($class) ? '' : " class=\"$class\""; |
| 117 | + return sprintf( "<tr>{$formatLN}<td%s>%s</td></tr>\n", |
| 118 | + $left, $right, |
| 119 | + $classAttr, $content |
| 120 | + ); |
| 121 | + } |
| 122 | + |
| 123 | + #### LINES HANDLERS ################################################ |
| 124 | + function handleLineDeletion( $line ) { |
| 125 | + $this->left++; |
| 126 | + return $this->formatLine( $line, 'del' ); |
| 127 | + } |
| 128 | + |
| 129 | + function handleLineAddition( $line ) { |
| 130 | + $this->right++; |
| 131 | + return $this->formatLine( $line, 'ins' ); |
| 132 | + } |
| 133 | + |
| 134 | + function handleChunkDelimiter( $line ) { |
| 135 | + $this->chunk++; |
| 136 | + |
| 137 | + list( |
| 138 | + $this->left, |
| 139 | + $leftChanged, # unused |
| 140 | + $this->right, |
| 141 | + $rightChanged # unused |
| 142 | + ) = $this->parseChunkDelimiter( $line ); |
| 143 | + |
| 144 | + return self::formatLine( $line, 'chunkdelimiter' ); |
| 145 | + } |
| 146 | + |
| 147 | + function handleUnchanged( $line ) { |
| 148 | + $this->left++; |
| 149 | + $this->right++; |
| 150 | + return $this->formatLine( $line, 'unchanged' ); |
| 151 | + } |
| 152 | + |
| 153 | + function handleLineFile( $line ) { |
| 154 | + return "<tr class=\"patchedfile\"><td colspan=\"3\">$line</td></tr>"; |
| 155 | + } |
| 156 | + #### END OF LINES HANDLERS ######################################### |
| 157 | + |
| 158 | + /** |
35 | 159 | * Turn a diff line into a properly formatted string suitable |
36 | 160 | * for output |
37 | 161 | * @param $line string Line from a diff |
Index: trunk/extensions/CodeReview/modules/ext.codereview.styles.css |
— | — | @@ -134,39 +134,41 @@ |
135 | 135 | .mw-codereview-diff table { |
136 | 136 | /* @noflip */direction: ltr; /* Source code is always LTR */ |
137 | 137 | |
138 | | - /* mimic MediaWiki <pre> style */ |
139 | 138 | font-family: monospace, "Courer New"; |
140 | 139 | line-height: 1.3em; |
141 | 140 | background-color: #F9F9F9; |
142 | | - border: 1px dashed #2F6FAB; |
| 141 | + border: 1px solid #CCC; |
143 | 142 | color: black; |
144 | 143 | |
145 | | - /* fix up space between <tr> */ |
| 144 | + /* fix up space between cells (cellspacing) */ |
146 | 145 | border-collapse: collapse; |
147 | 146 | } |
| 147 | + |
| 148 | +.mw-codereview-diff tr.patchedfile { |
| 149 | + background-color: #EEE; |
| 150 | + color: black; |
| 151 | +} |
| 152 | +.mw-codereview-diff tr.patchedfile td { |
| 153 | + padding: 1em; |
| 154 | + border: 1px solid #CCC; |
| 155 | +} |
| 156 | + |
148 | 157 | .mw-codereview-diff td { |
149 | | - margin:0; |
| 158 | + border: 1px #CCC; |
| 159 | + border-style: none solid; |
150 | 160 | |
151 | | - /* keep padding on left and right just like <pre> |
152 | | - * top bottom paddings are defined below for first/last childs |
153 | | - */ |
154 | | - padding:0 1em; |
155 | | - |
156 | 161 | /* respect white spaces just like <pre> */ |
157 | 162 | white-space: pre; |
158 | 163 | } |
159 | 164 | |
160 | | -/* "table border-collapse: collapse;" overrides padding |
161 | | - * The two next rules mimic <pre> padding by applying one to the first |
162 | | - * and last childs |
163 | | - */ |
164 | | -.mw-codereview-diff tr:first-child td { |
165 | | - padding-top: 1em; |
| 165 | +.mw-codereview-diff td.linenumbers{ |
| 166 | + background-color: #EEE; |
| 167 | + -webkit-user-select: none; |
| 168 | + -khtml-user-select: none; |
| 169 | + -moz-user-select: none; |
| 170 | + -o-user-select: none; |
| 171 | + user-select: none; |
166 | 172 | } |
167 | | -.mw-codereview-diff tr:last-child td { |
168 | | - padding-bottom: 1em; |
169 | | -} |
170 | | - |
171 | 173 | .mw-codereview-diff td.ins { |
172 | 174 | text-decoration: none; |
173 | 175 | color: green; |
— | — | @@ -175,6 +177,10 @@ |
176 | 178 | text-decoration: none; |
177 | 179 | color: red; |
178 | 180 | } |
| 181 | +.mw-codereview-diff td.chunkdelimiter { |
| 182 | + background-color: #EDEDFF; |
| 183 | + color: black; |
| 184 | +} |
179 | 185 | |
180 | 186 | .mw-codereview-diff .meta { |
181 | 187 | color: #008b8b; |