adding utf-16 support, long filename support and allow js wrapping for long text (bug 524237)

This commit is contained in:
Andy McKay 2011-04-11 15:40:18 -07:00
Родитель f6274003f7
Коммит a5acc6eae8
5 изменённых файлов: 104 добавлений и 98 удалений

Просмотреть файл

@ -1,3 +1,4 @@
import codecs
import mimetypes
import os
import shutil
@ -79,12 +80,15 @@ class FileViewer:
return True
def read_file(self, selected):
content = open(selected['full']).read()
try:
return content.decode('utf-8'), ''
except UnicodeDecodeError:
return (content.decode('utf-8', 'ignore'),
_('There were some problems decoding this file.'))
with open(selected['full'], 'r') as opened:
cont = opened.read()
codec = 'utf-16' if cont.startswith(codecs.BOM_UTF16) else 'utf-8'
try:
return cont.decode(codec), ''
except UnicodeDecodeError:
cont = cont.decode(codec, 'ignore')
#L10n: {0} is the filename.
return cont, _('Problems decoding using: %s.' % codec)
def get_files(self):
"""

Просмотреть файл

@ -31,7 +31,9 @@
<p>
<a href="#" id="files-prev">{{ _('Prev') }}</a> |
<a href="#" id="files-next">{{ _('Next') }}</a><br />
<a href="#" id="files-expand-all">{{ _('Expand All') }}</a>
<a href="#" id="files-expand-all">{{ _('Expand All') }}</a><br />
<a href="#" id="files-unwrap">{{ _('Unwrap text')}}</a>
<a href="#" id="files-wrap" class="hidden">{{ _('Wrap text')}}</a><br />
</p>
{% elif not files and status %}
@ -45,17 +47,15 @@
</div>
<div id="content-wrapper">
{% if msg %}
<p><strong>{{ msg }}</strong></p>
<p>{{ msg }}</p>
{% endif %}
<div id="numbers">
</div>
<div>
{% if viewer %}
{% if selected['binary'] and not selected['directory'] %}
<p>{{ _('Binary file, hash:') }} {{ selected.md5 }}</p>
{% else %}
{% if selected and content %}
<pre id="content">{{ content }}</pre>
<pre id="content" class="wrapped">{{ content }}</pre>
{% elif content == '' %}
<p>{{ _('No content.') }}</p>
{% endif %}
@ -63,15 +63,15 @@
{% endif %}
{% if diff and not diff.is_binary() %}
{% if text_one and text_two %}
<pre id="diff"></pre>
<pre id="diff" class="wrapped"></pre>
{% endif %}
{% endif %}
{% if diff and diff.is_binary() %}
<p>
{% if diff.is_different() %}
<strong>{{ _('Files are different.') }}</strong><br/>
{{ _('Files are different.') }}
{% else %}
<strong>{{ _('Files are the same.') }}</strong><br/>
{{ _('Files are the same.') }}
{% endif %}
</p>
{% endif %}

Просмотреть файл

@ -89,6 +89,11 @@ class TestFileHelper(test_utils.TestCase):
eq_(files['dictionaries/license.txt']['depth'], 1)
eq_(files['dictionaries/license.txt']['parent'], 'dictionaries')
def test_bom(self):
dest = tempfile.mkstemp()[1]
open(dest, 'w').write('foo'.encode('utf-16'))
eq_(self.viewer.read_file({'full': dest}), (u'foo', ''))
class TestDiffHelper(test_utils.TestCase):

Просмотреть файл

@ -3,68 +3,78 @@
padding-top: 1em
}
#file-viewer #files {
width: 15em;
#files {
float: left;
}
#file-viewer #files li a {
#files li a {
display: inline-block;
}
#file-viewer #numbers {
width: 3em;
float: left;
padding-left: 4em;
border-top: 1px solid white;
#content a {
padding: 0em;
margin: 0em;
}
#file-viewer #thinking, #file-viewer #content {
#content-wrapper, #thinking {
width: 50em;
float: left;
margin-left: 1em;
padding-left: 3em;
}
#content div.number, #diff div.number {
display: inline;
float: left;
vertical-align: top;
}
#content div.code, #diff div.code {
width: 50em;
display: block;
position: relative;
left: 3em;
padding-left: 1em;
}
.wrapped {
white-space: pre-wrap;
word-wrap: break-word;
}
pre div, pre ins, pre del {
display: inline-block;
padding: 0;
margin: 0;
width: 50em;
}
pre div:hover, pre ins:hover, pre del:hover {
background-color: #ffffcc;
}
pre, #file-viewer #numbers {
line-height: 1.15em;
}
pre ins {
background-color: #e6ffe6;
text-decoration: none;
line-height: inherit;
}
pre del {
background-color: #ffe6e6;
text-decoration: none;
line-height: inherit;
}
#file-viewer #content {
width: 10em;
#content, #diff {
background: white;
float: left;
}
#file-viewer .add {
background-color: #aae0aa;
.add {
background-color: #ddf8dd;
width: 100%;
}
#file-viewer .delete {
background-color: #ffaaaa;
.delete {
background-color: #ffdddd;
width: 100%;
}

Просмотреть файл

@ -1,27 +1,14 @@
if (typeof diff_match_patch !== 'undefined') {
diff_match_patch.prototype.diff_prettyHtml = function(diffs) {
/* An override of prettyHthml from diff_match_patch. This
one will not put any style attrs in the ins or del. It will
also as side effect write an array of line numbers, ignoring
deletions */
var html = [],
pattern_amp = /&/g,
pattern_lt = /</g,
pattern_gt = />/g,
pattern_para = /\n/g;
this.line_numbers = [];
var k = 1,
i = 0;
one will not put any style attrs in the ins or del. */
var html = [];
var k = 1;
for (var x = 0; x < diffs.length; x++) {
var op = diffs[x][0]; // Operation (insert, delete, equal)
var data = diffs[x][1]; // Text of change.
var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
.replace(pattern_gt, '&gt;').replace(pattern_para, '\n');
/* As as side effect, append on to the line_numbers a list
of numbers, with false for empty ones. So that <del> don't
have a line number. To get the numbers balanced, we need
to strip a starting or ending "" in the text */
var text = data.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
/* As as side effect, add in line numbers */
var lines = text.split('\n');
if (lines[lines.length-1] === '') {
lines.pop();
@ -30,29 +17,23 @@ if (typeof diff_match_patch !== 'undefined') {
lines.splice(0, 1);
}
for (var t = 0; t < lines.length; t++) {
if (op === DIFF_DELETE) {
this.line_numbers.push(false);
} else {
this.line_numbers.push(k++);
}
switch (op) {
case DIFF_INSERT:
html.push('<ins>+ ' + lines[t] + '</ins>');
html.push(format('<div><div class="number"><a href="#L{0}" name="L{0}">{0}</a>' +
'</div><div class="code add">{1}</div></div>', k, lines[t]));
k++;
break;
case DIFF_DELETE:
html.push('<del>- ' + lines[t] + '</del>');
html.push(format('<div><div class="number"></div>' +
'<div class="code delete">{0}</div></div>', lines[t]));
break;
case DIFF_EQUAL:
html.push('<div> ' + lines[t] + '</div>');
break;
}
if (op !== DIFF_DELETE) {
i += data.length;
html.push(format('<div><div class="number"><a href="#L{0}" name="L{0}">{0}</a>' +
'</div><div class="code">{1}</div></div>', k, lines[t]));
k++;
break;
}
}
}
return html.join('\n');
};
@ -62,42 +43,32 @@ function bind_viewer() {
function Viewer() {
this.$tree = $('#files ul');
this.compute = function() {
/* Counts the line numbers.
If we've got diffs, computes the diffs and the line numbers.
The line number computation is so that we don't show line numbers
on - lines. */
if ($('#content').length) {
var text = $('#content').text(),
length = text.split('\n').length,
num = [];
for (var k = 1; k < Math.max(1, length); k++) {
num.push(k);
var node = $('#content');
if (node.length) {
var splitted = node.text().split('\n'),
length = splitted.length,
html = [];
if (splitted.splice(length-1, length) == '') {
length = length - 1;
}
if (text.slice(text.length-1, text.length) !== '\n') {
num.push(num.slice(num.length-1, num.length) + 1);}
this.add_numbers(num);
for (var k = 0; k < splitted.length; k++) {
var text = splitted[k].replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
html.push(format('<div><div class="number"><a href="#L{0}" name="L{0}">{0}</a></div>' +
'<div class="code">{1}</div></div>', k+1, text));
}
node.html(html.join('\n'));
}
if ($('#diff').length) {
var dmp = new diff_match_patch();
var diff = dmp.diff_main($('#file-one').text(), $('#file-two').text());
$('#diff').html(dmp.diff_prettyHtml(diff));
this.add_numbers(dmp.line_numbers);
}
this.$tree.show();
};
this.add_numbers = function(num) {
/* Adds the line numbers into the page after counting. */
var text = [];
for (var k = 0; k < num.length; k++) {
text.push(num[k] === false ? '<br/>' : format('<a href="#L{0}" name="L{0}">{0}</a><br/>', num[k]));
}
// Because the line numbers are generated dynamically,
// it won't go to the anchor.
if (window.location.hash) {
window.location = window.location;
}
$('#numbers').html(text.join('\n'));
this.$tree.show();
};
this.show_leaf = function(names) {
/* Exposes the leaves for a given set of nodes. */
@ -147,10 +118,12 @@ function bind_viewer() {
shows it all. */
var self = this,
$thinking = $('#thinking'),
$wrapper = $('#wrapper');
$wrapper = $('#content-wrapper');
$wrapper.hide();
$thinking.removeClass('hidden').show();
history.pushState({ path: $link.text() }, '', $link.attr('href'));
if (history.pushState !== undefined) {
history.pushState({ path: $link.text() }, '', $link.attr('href'));
}
$('#content-wrapper').load($link.attr('href') + ' #content-wrapper', function() {
$(this).children().unwrap();
self.compute();
@ -190,13 +163,27 @@ function bind_viewer() {
if (choices.length) { viewer.select($(choices[0])); }
}));
$('#files-wrap').click(_pd(function() {
$('pre').addClass('wrapped');
$('#files-wrap').hide();
$('#files-unwrap').removeClass('hidden').show();
}));
$('#files-unwrap').click(_pd(function() {
$('pre').removeClass('wrapped');
$('#files-wrap').removeClass('hidden').show();
$('#files-unwrap').hide();
}));
$('#files-expand-all').click(_pd(function() {
viewer.$tree.find('li.hidden').removeClass('hidden').show();
viewer.$tree.find('a.directory').removeClass('closed').addClass('open');
}));
$('#files li a').click(_pd(function() {
viewer.$tree.find('.file').click(_pd(function() {
viewer.select($(this));
$('#files-unwrap').removeClass('hidden').show();
$('#files-wrap').hide();
}));
$(document).bind('keyup', _pd(function(e) {