r95043 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r95042‎ | r95043 | r95044 >
Date:21:00, 19 August 2011
Author:hashar
Status:resolved (Comments)
Tags:
Comment:
line numbers and better style

* new system to parse the diff, see parseLine() dispatcher.
* show lines numbering for each chunk.
* tweak style to replace the <pre> look'n feel, removing the first-child
last-child selectors.
* line numbers are not selected on mouse selection. Makes it easy to
copy paste the patch.

Note: old code left unchanged. To use it again, change the array_map
callback in splitLines from 'parseLine' to 'colorLine'.
Modified paths:
  • /trunk/extensions/CodeReview/backend/DiffHighlighter.php (modified) (history)
  • /trunk/extensions/CodeReview/modules/ext.codereview.styles.css (modified) (history)

Diff [purge]

Index: trunk/extensions/CodeReview/backend/DiffHighlighter.php
@@ -4,6 +4,9 @@
55 * Highlight a SVN diff for easier readibility
66 */
77 class CodeDiffHighlighter {
 8+ private $left = 0;
 9+ private $right = 0;
 10+ private $chunk = 0;
811
912 /**
1013 * Main entry point. Given a diff text, highlight it
@@ -26,11 +29,132 @@
2730 */
2831 function splitLines( $text ) {
2932 return implode( "\n",
30 - array_map( array( $this, 'colorLine' ),
 33+ array_map( array( $this, 'parseLine' ),
3134 explode( "\n", $text ) ) );
3235 }
3336
3437 /**
 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 = '&nbsp;';
 96+
 97+ switch( $class ) {
 98+ case 'chunkdelimiter':
 99+ $left = $right = '&mdash;';
 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+ /**
35159 * Turn a diff line into a properly formatted string suitable
36160 * for output
37161 * @param $line string Line from a diff
Index: trunk/extensions/CodeReview/modules/ext.codereview.styles.css
@@ -134,39 +134,41 @@
135135 .mw-codereview-diff table {
136136 /* @noflip */direction: ltr; /* Source code is always LTR */
137137
138 - /* mimic MediaWiki <pre> style */
139138 font-family: monospace, "Courer New";
140139 line-height: 1.3em;
141140 background-color: #F9F9F9;
142 - border: 1px dashed #2F6FAB;
 141+ border: 1px solid #CCC;
143142 color: black;
144143
145 - /* fix up space between <tr> */
 144+ /* fix up space between cells (cellspacing) */
146145 border-collapse: collapse;
147146 }
 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+
148157 .mw-codereview-diff td {
149 - margin:0;
 158+ border: 1px #CCC;
 159+ border-style: none solid;
150160
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 -
156161 /* respect white spaces just like <pre> */
157162 white-space: pre;
158163 }
159164
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;
166172 }
167 -.mw-codereview-diff tr:last-child td {
168 - padding-bottom: 1em;
169 -}
170 -
171173 .mw-codereview-diff td.ins {
172174 text-decoration: none;
173175 color: green;
@@ -175,6 +177,10 @@
176178 text-decoration: none;
177179 color: red;
178180 }
 181+.mw-codereview-diff td.chunkdelimiter {
 182+ background-color: #EDEDFF;
 183+ color: black;
 184+}
179185
180186 .mw-codereview-diff .meta {
181187 color: #008b8b;

Follow-up revisions

RevisionCommit summaryAuthorDate
r95501converts private var from r95043 to protected...hashar19:05, 25 August 2011
r95502converts &nbsp; to &#160 per cr on r95043...hashar19:05, 25 August 2011
r95599Follow-up r95043, htmlspecialchars() the contentjohnduhart14:59, 27 August 2011
r105542use Html::element instead of sprintf / htmlspecialchars...hashar12:19, 8 December 2011

Comments

#Comment by Reedy (talk | contribs)   22:50, 19 August 2011

/me wonders what Hashar is upto

#Comment by Hashar (talk | contribs)   09:28, 20 August 2011

I am much like Domas: total world domination by using open source software!

#Comment by Nikerabbit (talk | contribs)   13:30, 20 August 2011
+	private $left  = 0;
+	private $right = 0;
+	private $chunk = 0;

Why private?

+		$left = $right = '&nbsp;';

Use numerical entities or the symbol itself.

#Comment by Hashar (talk | contribs)   14:46, 21 August 2011

I don't see the need to use protected. One can still change it if the diffhighlighter is extended one day.

For the second comment, what is the reason to use ' ' instead of ' ' ? I found the later easier to understand.

#Comment by Nikerabbit (talk | contribs)   15:44, 21 August 2011

1) There seems to be consensus that protected should be the default value and that private/public should be used when necessary.

2) Ask Aryeh (Aryeh: can you write it down somewhere please, or point me to that?). It has to do with supporting xml parsers with certain document types that Mediawiki outputs (some of them don't define named entities at all).

#Comment by Hashar (talk | contribs)   21:03, 21 August 2011

Thanks for the explanation. I got the change in my working copy, need to fix it up a bit before committing.

Marking 'fixme' as a reminder.

#Comment by Hashar (talk | contribs)   19:06, 25 August 2011

Issues fixed by: - r95501 (private -> protected) - r95502 (nbsp -> #160)

#Comment by Johnduhart (talk | contribs)   14:47, 27 August 2011

This introduced problems with output not being escaped, really bad. http://cl.ly/9fXA

#Comment by Krinkle (talk | contribs)   13:11, 7 September 2011


Warning: array_map() [<a href='function.array-map'>function.array-map</a>]: An error occurred while invoking the map callback in C:\xampp\htdocs\mediawiki-trunk\extensions-trunk\CodeReview\backend\DiffHighlighter.php on line 82

#Comment by Reedy (talk | contribs)   14:34, 7 September 2011

Is it replicable?

#Comment by Krinkle (talk | contribs)   17:10, 7 September 2011

Yes, every single diff is unreadable because of this (it stops before the diff even starts).

Commenting out like the following is a temporary measure for our school wiki:

	#	case '@': // [[Special:Code/MediaWiki/95043|r95043]] CR –Krinkle
	#		$r = $this->handleChunkDelimiter( $line );
	#		break;
#Comment by Tim Starling (talk | contribs)   05:03, 8 December 2011

I've marked r94951 fixme for this.

#Comment by Tim Starling (talk | contribs)   05:04, 8 December 2011

Marking fixme for the stored XSS in formatLine(). Please escape both $class and $content. Use Html::element().

#Comment by Tim Starling (talk | contribs)   05:05, 8 December 2011

Sorry just $class and lack of Html::element(), I see $content was fixed already.

#Comment by Hashar (talk | contribs)   12:37, 8 December 2011

Those should be fine with follow up r105542

Status & tagging log