Changeset - 32471bd1f4ee
[Not reviewed]
beta
0 17 12
Marcin Kuzminski - 13 years ago 2012-11-05 19:57:29
marcin@python-works.com
Implemented generation of changesets based
on whole diff instead of per file diff. That
can give a big speed improvement for large changesets in
repositories with large history.
- improved handling of binary files
- show renames of binary files
- implemented new diff limit functionality
- unify diff generation between hg and git
- Added binary indicators for changed files,
- added diff lib tests
18 files changed:
0 comments (0 inline, 0 general)
rhodecode/controllers/changeset.py
Show inline comments
 
@@ -2,420 +2,344 @@
 
"""
 
    rhodecode.controllers.changeset
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    changeset controller for pylons showoing changes beetween
 
    revisions
 

	
 
    :created_on: Apr 25, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import logging
 
import traceback
 
from collections import defaultdict
 
from webob.exc import HTTPForbidden, HTTPBadRequest
 

	
 
from pylons import tmpl_context as c, url, request, response
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 
from pylons.decorators import jsonify
 

	
 
from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetError, \
 
    ChangesetDoesNotExistError
 
from rhodecode.lib.vcs.nodes import FileNode
 

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import action_logger
 
from rhodecode.lib.compat import OrderedDict
 
from rhodecode.lib import diffs
 
from rhodecode.model.db import ChangesetComment, ChangesetStatus
 
from rhodecode.model.comment import ChangesetCommentsModel
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.model.meta import Session
 
from rhodecode.lib.diffs import wrapped_diff
 
from rhodecode.lib.diffs import LimitedDiffContainer
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _update_with_GET(params, GET):
 
    for k in ['diff1', 'diff2', 'diff']:
 
        params[k] += GET.getall(k)
 

	
 

	
 
def anchor_url(revision, path, GET):
 
    fid = h.FID(revision, path)
 
    return h.url.current(anchor=fid, **dict(GET))
 

	
 

	
 
def get_ignore_ws(fid, GET):
 
    ig_ws_global = GET.get('ignorews')
 
    ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
 
    if ig_ws:
 
        try:
 
            return int(ig_ws[0].split(':')[-1])
 
        except:
 
            pass
 
    return ig_ws_global
 

	
 

	
 
def _ignorews_url(GET, fileid=None):
 
    fileid = str(fileid) if fileid else None
 
    params = defaultdict(list)
 
    _update_with_GET(params, GET)
 
    lbl = _('show white space')
 
    ig_ws = get_ignore_ws(fileid, GET)
 
    ln_ctx = get_line_ctx(fileid, GET)
 
    # global option
 
    if fileid is None:
 
        if ig_ws is None:
 
            params['ignorews'] += [1]
 
            lbl = _('ignore white space')
 
        ctx_key = 'context'
 
        ctx_val = ln_ctx
 
    # per file options
 
    else:
 
        if ig_ws is None:
 
            params[fileid] += ['WS:1']
 
            lbl = _('ignore white space')
 

	
 
        ctx_key = fileid
 
        ctx_val = 'C:%s' % ln_ctx
 
    # if we have passed in ln_ctx pass it along to our params
 
    if ln_ctx:
 
        params[ctx_key] += [ctx_val]
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
def get_line_ctx(fid, GET):
 
    ln_ctx_global = GET.get('context')
 
    if fid:
 
    ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
 
    else:
 
        _ln_ctx = filter(lambda k: k.startswith('C'), GET)
 
        ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx  else ln_ctx_global
 
        if ln_ctx:
 
            ln_ctx = [ln_ctx]
 

	
 
    if ln_ctx:
 
        retval = ln_ctx[0].split(':')[-1]
 
    else:
 
        retval = ln_ctx_global
 

	
 
    try:
 
        return int(retval)
 
    except:
 
        return
 
        return 3
 

	
 

	
 
def _context_url(GET, fileid=None):
 
    """
 
    Generates url for context lines
 

	
 
    :param fileid:
 
    """
 

	
 
    fileid = str(fileid) if fileid else None
 
    ig_ws = get_ignore_ws(fileid, GET)
 
    ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
 

	
 
    params = defaultdict(list)
 
    _update_with_GET(params, GET)
 

	
 
    # global option
 
    if fileid is None:
 
        if ln_ctx > 0:
 
            params['context'] += [ln_ctx]
 

	
 
        if ig_ws:
 
            ig_ws_key = 'ignorews'
 
            ig_ws_val = 1
 

	
 
    # per file option
 
    else:
 
        params[fileid] += ['C:%s' % ln_ctx]
 
        ig_ws_key = fileid
 
        ig_ws_val = 'WS:%s' % 1
 

	
 
    if ig_ws:
 
        params[ig_ws_key] += [ig_ws_val]
 

	
 
    lbl = _('%s line context') % ln_ctx
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
class ChangesetController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(ChangesetController, self).__before__()
 
        c.affected_files_cut_off = 60
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def index(self, revision):
 

	
 
        method = request.GET.get('diff', 'show')
 
        c.anchor_url = anchor_url
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 
        limit_off = request.GET.get('fulldiff')
 
        #get ranges of revisions if preset
 
        rev_range = revision.split('...')[:2]
 
        enable_comments = True
 
        try:
 
            if len(rev_range) == 2:
 
                enable_comments = False
 
                rev_start = rev_range[0]
 
                rev_end = rev_range[1]
 
                rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
 
                                                            end=rev_end)
 
            else:
 
                rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
 

	
 
            c.cs_ranges = list(rev_ranges)
 
            if not c.cs_ranges:
 
                raise RepositoryError('Changeset range returned empty result')
 

	
 
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
 
            log.error(traceback.format_exc())
 
            h.flash(str(e), category='warning')
 
            return redirect(url('home'))
 

	
 
        c.changes = OrderedDict()
 

	
 
        c.lines_added = 0  # count of lines added
 
        c.lines_deleted = 0  # count of lines removes
 

	
 
        cumulative_diff = 0
 
        c.cut_off = False  # defines if cut off limit is reached
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 
        c.comments = []
 
        c.statuses = []
 
        c.inline_comments = []
 
        c.inline_cnt = 0
 

	
 
        # Iterate over ranges (default changeset view is always one changeset)
 
        for changeset in c.cs_ranges:
 

	
 
            inlines = []
 
            if method == 'show':
 
            c.statuses.extend([ChangesetStatusModel()\
 
                              .get_status(c.rhodecode_db_repo.repo_id,
 
                                          changeset.raw_id)])
 

	
 
            c.comments.extend(ChangesetCommentsModel()\
 
                              .get_comments(c.rhodecode_db_repo.repo_id,
 
                                            revision=changeset.raw_id))
 
            inlines = ChangesetCommentsModel()\
 
                        .get_inline_comments(c.rhodecode_db_repo.repo_id,
 
                                             revision=changeset.raw_id)
 
            c.inline_comments.extend(inlines)
 

	
 
            c.changes[changeset.raw_id] = []
 
            try:
 
                changeset_parent = changeset.parents[0]
 
            except IndexError:
 
                changeset_parent = None
 

	
 
            cs2 = changeset.raw_id
 
            cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset()
 
            context_lcl = get_line_ctx('', request.GET)
 
            ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET)
 

	
 
            #==================================================================
 
            # ADDED FILES
 
            #==================================================================
 
            for node in changeset.added:
 
                fid = h.FID(revision, node.path)
 
                line_context_lcl = get_line_ctx(fid, request.GET)
 
                ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 
                lim = self.cut_off_limit
 
                if cumulative_diff > self.cut_off_limit:
 
                    lim = -1 if limit_off is None else None
 
                size, cs1, cs2, diff, st = wrapped_diff(
 
                    filenode_old=None,
 
                    filenode_new=node,
 
                    cut_off_limit=lim,
 
                    ignore_whitespace=ign_whitespace_lcl,
 
                    line_context=line_context_lcl,
 
                    enable_comments=enable_comments
 
                )
 
                cumulative_diff += size
 
            _diff = c.rhodecode_repo.get_diff(cs1, cs2,
 
                ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
 
            diff_limit = self.cut_off_limit if not limit_off else None
 
            diff_processor = diffs.DiffProcessor(_diff,
 
                                                 vcs=c.rhodecode_repo.alias,
 
                                                 format='gitdiff',
 
                                                 diff_limit=diff_limit)
 
            cs_changes = OrderedDict()
 
            if method == 'show':
 
                _parsed = diff_processor.prepare()
 
                c.limited_diff = False
 
                if isinstance(_parsed, LimitedDiffContainer):
 
                    c.limited_diff = True
 
                for f in _parsed:
 
                    st = f['stats']
 
                    if st[0] != 'b':
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
                c.changes[changeset.raw_id].append(
 
                    ('added', node, diff, cs1, cs2, st)
 
                )
 

	
 
            #==================================================================
 
            # CHANGED FILES
 
            #==================================================================
 
            for node in changeset.changed:
 
                try:
 
                    filenode_old = changeset_parent.get_node(node.path)
 
                except ChangesetError:
 
                    log.warning('Unable to fetch parent node for diff')
 
                    filenode_old = FileNode(node.path, '', EmptyChangeset())
 

	
 
                fid = h.FID(revision, node.path)
 
                line_context_lcl = get_line_ctx(fid, request.GET)
 
                ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 
                lim = self.cut_off_limit
 
                if cumulative_diff > self.cut_off_limit:
 
                    lim = -1 if limit_off is None else None
 
                size, cs1, cs2, diff, st = wrapped_diff(
 
                    filenode_old=filenode_old,
 
                    filenode_new=node,
 
                    cut_off_limit=lim,
 
                    ignore_whitespace=ign_whitespace_lcl,
 
                    line_context=line_context_lcl,
 
                    enable_comments=enable_comments
 
                )
 
                cumulative_diff += size
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
                c.changes[changeset.raw_id].append(
 
                    ('changed', node, diff, cs1, cs2, st)
 
                )
 
            #==================================================================
 
            # REMOVED FILES
 
            #==================================================================
 
            for node in changeset.removed:
 
                c.changes[changeset.raw_id].append(
 
                    ('removed', node, None, None, None, (0, 0))
 
                )
 
                    fid = h.FID(changeset.raw_id, f['filename'])
 
                    diff = diff_processor.as_html(enable_comments=enable_comments,
 
                                                  parsed_lines=[f])
 
                    cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'],
 
                                       diff, st]
 
            else:
 
                # downloads/raw we only need RAW diff nothing else
 
                diff = diff_processor.as_raw()
 
                cs_changes[''] = [None, None, None, None, diff, None]
 
            c.changes[changeset.raw_id] = cs_changes
 

	
 
        # count inline comments
 
        for __, lines in c.inline_comments:
 
            for comments in lines.values():
 
                c.inline_cnt += len(comments)
 

	
 
        if len(c.cs_ranges) == 1:
 
            c.changeset = c.cs_ranges[0]
 
            c.changes = c.changes[c.changeset.raw_id]
 

	
 
            c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id
 
                                     for x in c.changeset.parents])
 
        if method == 'download':
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s.patch' \
 
                                            % revision
 
            return render('changeset/raw_changeset.html')
 
        elif method == 'raw':
 
            response.content_type = 'text/plain'
 
            return render('changeset/raw_changeset.html')
 
        elif method == 'show':
 
            if len(c.cs_ranges) == 1:
 
            return render('changeset/changeset.html')
 
        else:
 
            return render('changeset/changeset_range.html')
 

	
 
    def raw_changeset(self, revision):
 

	
 
        method = request.GET.get('diff', 'show')
 
        ignore_whitespace = request.GET.get('ignorews') == '1'
 
        line_context = request.GET.get('context', 3)
 
        try:
 
            c.scm_type = c.rhodecode_repo.alias
 
            c.changeset = c.rhodecode_repo.get_changeset(revision)
 
        except RepositoryError:
 
            log.error(traceback.format_exc())
 
            return redirect(url('home'))
 
        else:
 
            try:
 
                c.changeset_parent = c.changeset.parents[0]
 
            except IndexError:
 
                c.changeset_parent = None
 
            c.changes = []
 

	
 
            for node in c.changeset.added:
 
                filenode_old = FileNode(node.path, '')
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = _('binary file') + '\n'
 
                else:
 
                    f_gitdiff = diffs.get_gitdiff(filenode_old, node,
 
                                           ignore_whitespace=ignore_whitespace,
 
                                           context=line_context)
 
                    diff = diffs.DiffProcessor(f_gitdiff,
 
                                                format='gitdiff').raw_diff()
 

	
 
                cs1 = None
 
                cs2 = node.changeset.raw_id
 
                c.changes.append(('added', node, diff, cs1, cs2))
 

	
 
            for node in c.changeset.changed:
 
                filenode_old = c.changeset_parent.get_node(node.path)
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = _('binary file')
 
                else:
 
                    f_gitdiff = diffs.get_gitdiff(filenode_old, node,
 
                                           ignore_whitespace=ignore_whitespace,
 
                                           context=line_context)
 
                    diff = diffs.DiffProcessor(f_gitdiff,
 
                                                format='gitdiff').raw_diff()
 

	
 
                cs1 = filenode_old.changeset.raw_id
 
                cs2 = node.changeset.raw_id
 
                c.changes.append(('changed', node, diff, cs1, cs2))
 

	
 
        response.content_type = 'text/plain'
 

	
 
        if method == 'download':
 
            response.content_disposition = 'attachment; filename=%s.patch' \
 
                                            % revision
 

	
 
        c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id
 
                                 for x in c.changeset.parents])
 

	
 
        c.diffs = ''
 
        for x in c.changes:
 
            c.diffs += x[2]
 

	
 
        return render('changeset/raw_changeset.html')
 
        return self.index(revision)
 

	
 
    @jsonify
 
    def comment(self, repo_name, revision):
 
        status = request.POST.get('changeset_status')
 
        change_status = request.POST.get('change_changeset_status')
 
        text = request.POST.get('text')
 
        if status and change_status:
 
            text = text or (_('Status change -> %s')
 
                            % ChangesetStatus.get_status_lbl(status))
 

	
 
        comm = ChangesetCommentsModel().create(
 
            text=text,
 
            repo=c.rhodecode_db_repo.repo_id,
 
            user=c.rhodecode_user.user_id,
 
            revision=revision,
 
            f_path=request.POST.get('f_path'),
 
            line_no=request.POST.get('line'),
 
            status_change=(ChangesetStatus.get_status_lbl(status)
 
                           if status and change_status else None)
 
        )
 

	
 
        # get status if set !
 
        if status and change_status:
 
            # if latest status was from pull request and it's closed
 
            # disallow changing status !
 
            # dont_allow_on_closed_pull_request = True !
 

	
 
            try:
 
                ChangesetStatusModel().set_status(
 
                    c.rhodecode_db_repo.repo_id,
 
                    status,
 
                    c.rhodecode_user.user_id,
 
                    comm,
 
                    revision=revision,
 
                    dont_allow_on_closed_pull_request=True
 
                )
 
            except StatusChangeOnClosedPullRequestError:
 
                log.error(traceback.format_exc())
 
                msg = _('Changing status on a changeset associated with'
 
                        'a closed pull request is not allowed')
 
                h.flash(msg, category='warning')
 
                return redirect(h.url('changeset_home', repo_name=repo_name,
 
                                      revision=revision))
 
        action_logger(self.rhodecode_user,
 
                      'user_commented_revision:%s' % revision,
 
                      c.rhodecode_db_repo, self.ip_addr, self.sa)
 

	
 
        Session().commit()
rhodecode/controllers/compare.py
Show inline comments
 
@@ -97,52 +97,52 @@ class CompareController(BaseRepoControll
 

	
 
        c.org_repo = org_repo = Repository.get_by_repo_name(org_repo)
 
        c.other_repo = other_repo = Repository.get_by_repo_name(other_repo)
 

	
 
        if c.org_repo is None or c.other_repo is None:
 
            log.error('Could not found repo %s or %s' % (org_repo, other_repo))
 
            raise HTTPNotFound
 

	
 
        if c.org_repo.scm_instance.alias != 'hg':
 
            log.error('Review not available for GIT REPOS')
 
            raise HTTPNotFound
 
        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
 
        self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
 
        self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
 

	
 
        c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
 
                                    org_repo, org_ref, other_repo, other_ref
 
                                    )
 

	
 
        c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
 
                                                   c.cs_ranges])
 
        c.target_repo = c.repo_name
 
        # defines that we need hidden inputs with changesets
 
        c.as_form = request.GET.get('as_form', False)
 
        if partial:
 
            return render('compare/compare_cs.html')
 

	
 
        if not bundle_compare and c.cs_ranges:
 
            # case we want a simple diff without incoming changesets, just
 
            # for review purposes. Make the diff on the forked repo, with
 
            # revision that is common ancestor
 
            other_ref = ('rev', c.cs_ranges[-1].parents[0].raw_id)
 
            other_repo = org_repo
 

	
 
        c.org_ref = org_ref[1]
 
        c.other_ref = other_ref[1]
 

	
 
        _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
 
                             discovery_data, bundle_compare=bundle_compare)
 
        diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
 
        _parsed = diff_processor.prepare()
 

	
 
        c.files = []
 
        c.changes = {}
 

	
 
        for f in _parsed:
 
            fid = h.FID('', f['filename'])
 
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
 
            diff = diff_processor.as_html(enable_comments=False, diff_lines=[f])
 
            diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f])
 
            c.changes[fid] = [f['operation'], f['filename'], diff]
 

	
 
        return render('compare/compare_diff.html')
rhodecode/controllers/files.py
Show inline comments
 
@@ -393,158 +393,176 @@ class FilesController(BaseRepoController
 
        except ChangesetDoesNotExistError:
 
            return _('Unknown revision %s') % revision
 
        except EmptyRepositoryError:
 
            return _('Empty repository')
 
        except (ImproperArchiveTypeError, KeyError):
 
            return _('Unknown archive type')
 

	
 
        fd, archive = tempfile.mkstemp()
 
        t = open(archive, 'wb')
 
        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
 
        t.close()
 

	
 
        def get_chunked_archive(archive):
 
            stream = open(archive, 'rb')
 
            while True:
 
                data = stream.read(16 * 1024)
 
                if not data:
 
                    stream.close()
 
                    os.close(fd)
 
                    os.remove(archive)
 
                    break
 
                yield data
 

	
 
        response.content_disposition = str('attachment; filename=%s-%s%s' \
 
                                           % (repo_name, revision[:12], ext))
 
        response.content_type = str(content_type)
 
        return get_chunked_archive(archive)
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def diff(self, repo_name, f_path):
 
        ignore_whitespace = request.GET.get('ignorews') == '1'
 
        line_context = request.GET.get('context', 3)
 
        diff1 = request.GET.get('diff1', '')
 
        diff2 = request.GET.get('diff2', '')
 
        c.action = request.GET.get('diff')
 
        c.no_changes = diff1 == diff2
 
        c.f_path = f_path
 
        c.big_diff = False
 
        c.anchor_url = anchor_url
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 
        c.changes = OrderedDict()
 
        c.changes[diff2] = []
 

	
 
        #special case if we want a show rev only, it's impl here
 
        #to reduce JS and callbacks
 

	
 
        if request.GET.get('show_rev'):
 
            if str2bool(request.GET.get('annotate', 'False')):
 
                _url = url('files_annotate_home', repo_name=c.repo_name,
 
                           revision=diff1, f_path=c.f_path)
 
            else:
 
                _url = url('files_home', repo_name=c.repo_name,
 
                           revision=diff1, f_path=c.f_path)
 

	
 
            return redirect(_url)
 
        try:
 
            if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
 
                c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
 
                try:
 
                node1 = c.changeset_1.get_node(f_path)
 
                except NodeDoesNotExistError:
 
                    c.changeset_1 = EmptyChangeset(cs=diff1,
 
                                                   revision=c.changeset_1.revision,
 
                                                   repo=c.rhodecode_repo)
 
                    node1 = FileNode(f_path, '', changeset=c.changeset_1)
 
            else:
 
                c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
 
                node1 = FileNode('.', '', changeset=c.changeset_1)
 
                node1 = FileNode(f_path, '', changeset=c.changeset_1)
 

	
 
            if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
 
                c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
 
                try:
 
                node2 = c.changeset_2.get_node(f_path)
 
                except NodeDoesNotExistError:
 
                    c.changeset_2 = EmptyChangeset(cs=diff2,
 
                                                   revision=c.changeset_2.revision,
 
                                                   repo=c.rhodecode_repo)
 
                    node2 = FileNode(f_path, '', changeset=c.changeset_2)
 
            else:
 
                c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
 
                node2 = FileNode('.', '', changeset=c.changeset_2)
 
                node2 = FileNode(f_path, '', changeset=c.changeset_2)
 
        except RepositoryError:
 
            log.error(traceback.format_exc())
 
            return redirect(url('files_home', repo_name=c.repo_name,
 
                                f_path=f_path))
 

	
 
        if c.action == 'download':
 
            _diff = diffs.get_gitdiff(node1, node2,
 
                                      ignore_whitespace=ignore_whitespace,
 
                                      context=line_context)
 
            diff = diffs.DiffProcessor(_diff, format='gitdiff')
 

	
 
            diff_name = '%s_vs_%s.diff' % (diff1, diff2)
 
            response.content_type = 'text/plain'
 
            response.content_disposition = (
 
                'attachment; filename=%s' % diff_name
 
            )
 
            return diff.raw_diff()
 
            return diff.as_raw()
 

	
 
        elif c.action == 'raw':
 
            _diff = diffs.get_gitdiff(node1, node2,
 
                                      ignore_whitespace=ignore_whitespace,
 
                                      context=line_context)
 
            diff = diffs.DiffProcessor(_diff, format='gitdiff')
 
            response.content_type = 'text/plain'
 
            return diff.raw_diff()
 
            return diff.as_raw()
 

	
 
        else:
 
            fid = h.FID(diff2, node2.path)
 
            line_context_lcl = get_line_ctx(fid, request.GET)
 
            ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 

	
 
            lim = request.GET.get('fulldiff') or self.cut_off_limit
 
            _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
 
                                         filenode_new=node2,
 
                                         cut_off_limit=lim,
 
                                         ignore_whitespace=ign_whitespace_lcl,
 
                                         line_context=line_context_lcl,
 
                                         enable_comments=False)
 

	
 
            c.changes = [('', node2, diff, cs1, cs2, st,)]
 
            op = ''
 
            filename = node1.path
 
            cs_changes = {
 
                'fid': [cs1, cs2, op, filename, diff, st]
 
            }
 
            c.changes = cs_changes
 

	
 
        return render('files/file_diff.html')
 

	
 
    def _get_node_history(self, cs, f_path, changesets=None):
 
        """
 
        get changesets history for given node
 

	
 
        :param cs: changeset to calculate history
 
        :param f_path: path for node to calculate history for
 
        :param changesets: if passed don't calculate history and take
 
            changesets defined in this list
 
        """
 
        # calculate history based on tip
 
        tip_cs = c.rhodecode_repo.get_changeset()
 
        if changesets is None:
 
            try:
 
                changesets = tip_cs.get_file_history(f_path)
 
            except (NodeDoesNotExistError, ChangesetError):
 
                #this node is not present at tip !
 
                changesets = cs.get_file_history(f_path)
 

	
 
        hist_l = []
 

	
 
        changesets_group = ([], _("Changesets"))
 
        branches_group = ([], _("Branches"))
 
        tags_group = ([], _("Tags"))
 
        _hg = cs.repository.alias == 'hg'
 
        for chs in changesets:
 
            _branch = '(%s)' % chs.branch if _hg else ''
 
            n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
 
            changesets_group[0].append((chs.raw_id, n_desc,))
 

	
 
        hist_l.append(changesets_group)
 

	
 
        for name, chs in c.rhodecode_repo.branches.items():
 
            branches_group[0].append((chs, name),)
 
        hist_l.append(branches_group)
 

	
 
        for name, chs in c.rhodecode_repo.tags.items():
 
            tags_group[0].append((chs, name),)
 
        hist_l.append(tags_group)
 

	
 
        return hist_l, changesets
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    @jsonify
rhodecode/controllers/pullrequests.py
Show inline comments
 
@@ -254,97 +254,97 @@ class PullrequestsController(BaseRepoCon
 

	
 
        org_repo = pull_request.org_repo
 
        (org_ref_type,
 
         org_ref_name,
 
         org_ref_rev) = pull_request.org_ref.split(':')
 

	
 
        other_repo = pull_request.other_repo
 
        (other_ref_type,
 
         other_ref_name,
 
         other_ref_rev) = pull_request.other_ref.split(':')
 

	
 
        # despite opening revisions for bookmarks/branches/tags, we always
 
        # convert this to rev to prevent changes after book or branch change
 
        org_ref = ('rev', org_ref_rev)
 
        other_ref = ('rev', other_ref_rev)
 

	
 
        c.org_repo = org_repo
 
        c.other_repo = other_repo
 

	
 
        c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
 
                                       org_repo, org_ref, other_repo, other_ref
 
                                      )
 
        if c.cs_ranges:
 
            # case we want a simple diff without incoming changesets, just
 
            # for review purposes. Make the diff on the forked repo, with
 
            # revision that is common ancestor
 
            other_ref = ('rev', c.cs_ranges[-1].parents[0].raw_id)
 
            other_repo = org_repo
 

	
 
        c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
 
        # defines that we need hidden inputs with changesets
 
        c.as_form = request.GET.get('as_form', False)
 

	
 
        c.org_ref = org_ref[1]
 
        c.other_ref = other_ref[1]
 
        # diff needs to have swapped org with other to generate proper diff
 
        _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
 
                             discovery_data)
 
        diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
 
        _parsed = diff_processor.prepare()
 

	
 
        c.files = []
 
        c.changes = {}
 

	
 
        for f in _parsed:
 
            fid = h.FID('', f['filename'])
 
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
 
            diff = diff_processor.as_html(enable_comments=enable_comments,
 
                                          diff_lines=[f])
 
                                          parsed_lines=[f])
 
            c.changes[fid] = [f['operation'], f['filename'], diff]
 

	
 
    def show(self, repo_name, pull_request_id):
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 
        c.pull_request = PullRequest.get_or_404(pull_request_id)
 
        c.target_repo = c.pull_request.org_repo.repo_name
 

	
 
        cc_model = ChangesetCommentsModel()
 
        cs_model = ChangesetStatusModel()
 
        _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
 
                                            pull_request=c.pull_request,
 
                                            with_revisions=True)
 

	
 
        cs_statuses = defaultdict(list)
 
        for st in _cs_statuses:
 
            cs_statuses[st.author.username] += [st]
 

	
 
        c.pull_request_reviewers = []
 
        c.pull_request_pending_reviewers = []
 
        for o in c.pull_request.reviewers:
 
            st = cs_statuses.get(o.user.username, None)
 
            if st:
 
                sorter = lambda k: k.version
 
                st = [(x, list(y)[0])
 
                      for x, y in (groupby(sorted(st, key=sorter), sorter))]
 
            else:
 
                c.pull_request_pending_reviewers.append(o.user)
 
            c.pull_request_reviewers.append([o.user, st])
 

	
 
        # pull_requests repo_name we opened it against
 
        # ie. other_repo must match
 
        if repo_name != c.pull_request.other_repo.repo_name:
 
            raise HTTPNotFound
 

	
 
        # load compare data into template context
 
        enable_comments = not c.pull_request.is_closed()
 
        self._load_compare_data(c.pull_request, enable_comments=enable_comments)
 

	
 
        # inline comments
 
        c.inline_cnt = 0
 
        c.inline_comments = cc_model.get_inline_comments(
 
                                c.rhodecode_db_repo.repo_id,
 
                                pull_request=pull_request_id)
 
        # count inline comments
 
        for __, lines in c.inline_comments:
 
            for comments in lines.values():
rhodecode/lib/diffs.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.diffs
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Set of diffing helpers, previously part of vcs
 

	
 

	
 
    :created_on: Dec 4, 2011
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :original copyright: 2007-2008 by Armin Ronacher
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import re
 
import difflib
 
import logging
 
import traceback
 

	
 
from itertools import tee, imap
 

	
 
from mercurial import patch
 
from mercurial.mdiff import diffopts
 
from mercurial.bundlerepo import bundlerepository
 

	
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib.compat import BytesIO
 
from rhodecode.lib.vcs.utils.hgcompat import localrepo
 
from rhodecode.lib.vcs.exceptions import VCSError
 
from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.helpers import escape
 
from rhodecode.lib.utils import make_ui
 
from rhodecode.lib.utils2 import safe_unicode
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def wrap_to_table(str_):
 
    return '''<table class="code-difftable">
 
                <tr class="line no-comment">
 
                <td class="lineno new"></td>
 
                <td class="code no-comment"><pre>%s</pre></td>
 
                </tr>
 
              </table>''' % str_
 

	
 

	
 
def wrapped_diff(filenode_old, filenode_new, cut_off_limit=None,
 
                ignore_whitespace=True, line_context=3,
 
                enable_comments=False):
 
    """
 
    returns a wrapped diff into a table, checks for cut_off_limit and presents
 
    proper message
 
    """
 

	
 
    if filenode_old is None:
 
        filenode_old = FileNode(filenode_new.path, '', EmptyChangeset())
 

	
 
    if filenode_old.is_binary or filenode_new.is_binary:
 
        diff = wrap_to_table(_('binary file'))
 
        stats = (0, 0)
 
        size = 0
 

	
 
    elif cut_off_limit != -1 and (cut_off_limit is None or
 
    (filenode_old.size < cut_off_limit and filenode_new.size < cut_off_limit)):
 
@@ -85,563 +86,681 @@ def wrapped_diff(filenode_old, filenode_
 
        diff = diff_processor.as_html(enable_comments=enable_comments)
 
        stats = diff_processor.stat()
 
        size = len(diff or '')
 
    else:
 
        diff = wrap_to_table(_('Changeset was too big and was cut off, use '
 
                               'diff menu to display this diff'))
 
        stats = (0, 0)
 
        size = 0
 
    if not diff:
 
        submodules = filter(lambda o: isinstance(o, SubModuleNode),
 
                            [filenode_new, filenode_old])
 
        if submodules:
 
            diff = wrap_to_table(escape('Submodule %r' % submodules[0]))
 
        else:
 
            diff = wrap_to_table(_('No changes detected'))
 

	
 
    cs1 = filenode_old.changeset.raw_id
 
    cs2 = filenode_new.changeset.raw_id
 

	
 
    return size, cs1, cs2, diff, stats
 

	
 

	
 
def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3):
 
    """
 
    Returns git style diff between given ``filenode_old`` and ``filenode_new``.
 

	
 
    :param ignore_whitespace: ignore whitespaces in diff
 
    """
 
    # make sure we pass in default context
 
    context = context or 3
 
    submodules = filter(lambda o: isinstance(o, SubModuleNode),
 
                        [filenode_new, filenode_old])
 
    if submodules:
 
        return ''
 

	
 
    for filenode in (filenode_old, filenode_new):
 
        if not isinstance(filenode, FileNode):
 
            raise VCSError("Given object should be FileNode object, not %s"
 
                % filenode.__class__)
 

	
 
    repo = filenode_new.changeset.repository
 
    old_raw_id = getattr(filenode_old.changeset, 'raw_id', repo.EMPTY_CHANGESET)
 
    new_raw_id = getattr(filenode_new.changeset, 'raw_id', repo.EMPTY_CHANGESET)
 

	
 
    vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path,
 
                                 ignore_whitespace, context)
 
    return vcs_gitdiff
 

	
 
NEW_FILENODE = 1
 
DEL_FILENODE = 2
 
MOD_FILENODE = 3
 
RENAMED_FILENODE = 4
 
CHMOD_FILENODE = 5
 

	
 

	
 
class DiffLimitExceeded(Exception):
 
    pass
 

	
 

	
 
class LimitedDiffContainer(object):
 

	
 
    def __init__(self, diff_limit, cur_diff_size, diff):
 
        self.diff = diff
 
        self.diff_limit = diff_limit
 
        self.cur_diff_size = cur_diff_size
 

	
 
    def __iter__(self):
 
        for l in self.diff:
 
            yield l
 

	
 

	
 
class DiffProcessor(object):
 
    """
 
    Give it a unified diff and it returns a list of the files that were
 
    Give it a unified or git diff and it returns a list of the files that were
 
    mentioned in the diff together with a dict of meta information that
 
    can be used to render it in a HTML template.
 
    """
 
    _chunk_re = re.compile(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
 
    _newline_marker = '\\ No newline at end of file\n'
 
    _git_header_re = re.compile(r"""
 
        #^diff[ ]--git
 
            [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
 
        (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
 
           ^rename[ ]from[ ](?P<rename_from>\S+)\n
 
           ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
 
        (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
 
           ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
 
        (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
 
        (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
 
        (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
 
            \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
 
        (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
 
        (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
 
    """, re.VERBOSE | re.MULTILINE)
 
    _hg_header_re = re.compile(r"""
 
        #^diff[ ]--git
 
            [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
 
        (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
 
        (?:^rename[ ]from[ ](?P<rename_from>\S+)\n
 
           ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
 
        (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
 
           ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
 
        (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
 
        (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
 
        (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
 
            \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
 
        (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
 
        (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
 
    """, re.VERBOSE | re.MULTILINE)
 

	
 
    def __init__(self, diff, differ='diff', format='gitdiff'):
 
        """
 
        :param diff:   a text in diff format or generator
 
        :param format: format of diff passed, `udiff` or `gitdiff`
 
    def __init__(self, diff, vcs='hg', format='gitdiff', diff_limit=None):
 
        """
 
        if isinstance(diff, basestring):
 
            diff = [diff]
 
        :param diff:   a text in diff format
 
        :param vcs: type of version controll hg or git
 
        :param format: format of diff passed, `udiff` or `gitdiff`
 
        :param diff_limit: define the size of diff that is considered "big"
 
            based on that parameter cut off will be triggered, set to None
 
            to show full diff
 
        """
 
        if not isinstance(diff, basestring):
 
            raise Exception('Diff must be a basestring got %s instead' % type(diff))
 

	
 
        self.__udiff = diff
 
        self.__format = format
 
        self._diff = diff
 
        self._format = format
 
        self.adds = 0
 
        self.removes = 0
 

	
 
        if isinstance(self.__udiff, basestring):
 
            self.lines = iter(self.__udiff.splitlines(1))
 
        # calculate diff size
 
        self.diff_size = len(diff)
 
        self.diff_limit = diff_limit
 
        self.cur_diff_size = 0
 
        self.parsed = False
 
        self.parsed_diff = []
 
        self.vcs = vcs
 

	
 
        elif self.__format == 'gitdiff':
 
            udiff_copy = self.copy_iterator()
 
            self.lines = imap(self.escaper, self._parse_gitdiff(udiff_copy))
 
        else:
 
            udiff_copy = self.copy_iterator()
 
            self.lines = imap(self.escaper, udiff_copy)
 

	
 
        # Select a differ.
 
        if differ == 'difflib':
 
        if format == 'gitdiff':
 
            self.differ = self._highlight_line_difflib
 
            self._parser = self._parse_gitdiff
 
        else:
 
            self.differ = self._highlight_line_udiff
 
            self._parser = self._parse_udiff
 

	
 
    def escaper(self, string):
 
        return string.replace('&', '&amp;')\
 
                .replace('<', '&lt;')\
 
                .replace('>', '&gt;')
 

	
 
    def copy_iterator(self):
 
    def _copy_iterator(self):
 
        """
 
        make a fresh copy of generator, we should not iterate thru
 
        an original as it's needed for repeating operations on
 
        this instance of DiffProcessor
 
        """
 
        self.__udiff, iterator_copy = tee(self.__udiff)
 
        return iterator_copy
 

	
 
    def _extract_rev(self, line1, line2):
 
    def _escaper(self, string):
 
        """
 
        Extract the operation (A/M/D), filename and revision hint from a line.
 
        Escaper for diff escapes special chars and checks the diff limit
 

	
 
        :param string:
 
        :type string:
 
        """
 

	
 
        try:
 
            if line1.startswith('--- ') and line2.startswith('+++ '):
 
                l1 = line1[4:].split(None, 1)
 
                old_filename = (l1[0].replace('a/', '', 1)
 
                                if len(l1) >= 1 else None)
 
                old_rev = l1[1] if len(l1) == 2 else 'old'
 
        self.cur_diff_size += len(string)
 

	
 
                l2 = line2[4:].split(None, 1)
 
                new_filename = (l2[0].replace('b/', '', 1)
 
                                if len(l1) >= 1 else None)
 
                new_rev = l2[1] if len(l2) == 2 else 'new'
 
        # escaper get's iterated on each .next() call and it checks if each
 
        # parsed line doesn't exceed the diff limit
 
        if self.diff_limit is not None and self.cur_diff_size > self.diff_limit:
 
            raise DiffLimitExceeded('Diff Limit Exceeded')
 

	
 
                filename = (old_filename
 
                            if old_filename != '/dev/null' else new_filename)
 

	
 
                operation = 'D' if new_filename == '/dev/null' else None
 
                if not operation:
 
                    operation = 'M' if old_filename != '/dev/null' else 'A'
 
        return safe_unicode(string).replace('&', '&amp;')\
 
                .replace('<', '&lt;')\
 
                .replace('>', '&gt;')
 

	
 
                return operation, filename, new_rev, old_rev
 
        except (ValueError, IndexError):
 
            pass
 
    def _line_counter(self, l):
 
        """
 
        Checks each line and bumps total adds/removes for this diff
 

	
 
        return None, None, None, None
 

	
 
    def _parse_gitdiff(self, diffiterator):
 
        def line_decoder(l):
 
        :param l:
 
        """
 
            if l.startswith('+') and not l.startswith('+++'):
 
                self.adds += 1
 
            elif l.startswith('-') and not l.startswith('---'):
 
                self.removes += 1
 
            return safe_unicode(l)
 

	
 
        output = list(diffiterator)
 
        size = len(output)
 

	
 
        if size == 2:
 
            l = []
 
            l.extend([output[0]])
 
            l.extend(output[1].splitlines(1))
 
            return map(line_decoder, l)
 
        elif size == 1:
 
            return  map(line_decoder, output[0].splitlines(1))
 
        elif size == 0:
 
            return []
 

	
 
        raise Exception('wrong size of diff %s' % size)
 
        return l
 

	
 
    def _highlight_line_difflib(self, line, next_):
 
        """
 
        Highlight inline changes in both lines.
 
        """
 

	
 
        if line['action'] == 'del':
 
            old, new = line, next_
 
        else:
 
            old, new = next_, line
 

	
 
        oldwords = re.split(r'(\W)', old['line'])
 
        newwords = re.split(r'(\W)', new['line'])
 

	
 
        sequence = difflib.SequenceMatcher(None, oldwords, newwords)
 

	
 
        oldfragments, newfragments = [], []
 
        for tag, i1, i2, j1, j2 in sequence.get_opcodes():
 
            oldfrag = ''.join(oldwords[i1:i2])
 
            newfrag = ''.join(newwords[j1:j2])
 
            if tag != 'equal':
 
                if oldfrag:
 
                    oldfrag = '<del>%s</del>' % oldfrag
 
                if newfrag:
 
                    newfrag = '<ins>%s</ins>' % newfrag
 
            oldfragments.append(oldfrag)
 
            newfragments.append(newfrag)
 

	
 
        old['line'] = "".join(oldfragments)
 
        new['line'] = "".join(newfragments)
 

	
 
    def _highlight_line_udiff(self, line, next_):
 
        """
 
        Highlight inline changes in both lines.
 
        """
 
        start = 0
 
        limit = min(len(line['line']), len(next_['line']))
 
        while start < limit and line['line'][start] == next_['line'][start]:
 
            start += 1
 
        end = -1
 
        limit -= start
 
        while -end <= limit and line['line'][end] == next_['line'][end]:
 
            end -= 1
 
        end += 1
 
        if start or end:
 
            def do(l):
 
                last = end + len(l['line'])
 
                if l['action'] == 'add':
 
                    tag = 'ins'
 
                else:
 
                    tag = 'del'
 
                l['line'] = '%s<%s>%s</%s>%s' % (
 
                    l['line'][:start],
 
                    tag,
 
                    l['line'][start:last],
 
                    tag,
 
                    l['line'][last:]
 
                )
 
            do(line)
 
            do(next_)
 

	
 
    def _get_header(self, diff_chunk):
 
        """
 
        parses the diff header, and returns parts, and leftover diff
 
        parts consists of 14 elements::
 

	
 
            a_path, b_path, similarity_index, rename_from, rename_to,
 
            old_mode, new_mode, new_file_mode, deleted_file_mode,
 
            a_blob_id, b_blob_id, b_mode, a_file, b_file
 

	
 
        :param diff_chunk:
 
        :type diff_chunk:
 
        """
 

	
 
        if self.vcs == 'git':
 
            match = self._git_header_re.match(diff_chunk)
 
            diff = diff_chunk[match.end():]
 
            return match.groupdict(), imap(self._escaper, diff.splitlines(1))
 
        elif self.vcs == 'hg':
 
            match = self._hg_header_re.match(diff_chunk)
 
            diff = diff_chunk[match.end():]
 
            return match.groupdict(), imap(self._escaper, diff.splitlines(1))
 
        else:
 
            raise Exception('VCS type %s is not supported' % self.vcs)
 

	
 
    def _parse_gitdiff(self, inline_diff=True):
 
        _files = []
 
        diff_container = lambda arg: arg
 

	
 
        ##split the diff in chunks of separate --git a/file b/file chunks
 
        for raw_diff in ('\n' + self._diff).split('\ndiff --git')[1:]:
 
            binary = False
 
            binary_msg = 'unknown binary'
 
            head, diff = self._get_header(raw_diff)
 

	
 
            if not head['a_file'] and head['b_file']:
 
                op = 'A'
 
            elif head['a_file'] and head['b_file']:
 
                op = 'M'
 
            elif head['a_file'] and not head['b_file']:
 
                op = 'D'
 
            else:
 
                #probably we're dealing with a binary file 1
 
                binary = True
 
                if head['deleted_file_mode']:
 
                    op = 'D'
 
                    stats = ['b', DEL_FILENODE]
 
                    binary_msg = 'deleted binary file'
 
                elif head['new_file_mode']:
 
                    op = 'A'
 
                    stats = ['b', NEW_FILENODE]
 
                    binary_msg = 'new binary file %s' % head['new_file_mode']
 
                else:
 
                    if head['new_mode'] and head['old_mode']:
 
                        stats = ['b', CHMOD_FILENODE]
 
                        op = 'M'
 
                        binary_msg = ('modified binary file chmod %s => %s'
 
                                      % (head['old_mode'], head['new_mode']))
 
                    elif (head['rename_from'] and head['rename_to']
 
                          and head['rename_from'] != head['rename_to']):
 
                        stats = ['b', RENAMED_FILENODE]
 
                        op = 'M'
 
                        binary_msg = ('file renamed from %s to %s'
 
                                      % (head['rename_from'], head['rename_to']))
 
                    else:
 
                        stats = ['b', MOD_FILENODE]
 
                        op = 'M'
 
                        binary_msg = 'modified binary file'
 

	
 
            if not binary:
 
                try:
 
                    chunks, stats = self._parse_lines(diff)
 
                except DiffLimitExceeded:
 
                    diff_container = lambda _diff: LimitedDiffContainer(
 
                                                self.diff_limit,
 
                                                self.cur_diff_size,
 
                                                _diff)
 
                    break
 
            else:
 
                chunks = []
 
                chunks.append([{
 
                    'old_lineno': '',
 
                    'new_lineno': '',
 
                    'action':     'binary',
 
                    'line':       binary_msg,
 
                }])
 

	
 
            _files.append({
 
                'filename':         head['b_path'],
 
                'old_revision':     head['a_blob_id'],
 
                'new_revision':     head['b_blob_id'],
 
                'chunks':           chunks,
 
                'operation':        op,
 
                'stats':            stats,
 
            })
 

	
 
        sorter = lambda info: {'A': 0, 'M': 1, 'D': 2}.get(info['operation'])
 

	
 
        if inline_diff is False:
 
            return diff_container(sorted(_files, key=sorter))
 

	
 
        # highlight inline changes
 
        for diff_data in _files:
 
            for chunk in diff_data['chunks']:
 
                lineiter = iter(chunk)
 
                try:
 
                    while 1:
 
                        line = lineiter.next()
 
                        if line['action'] not in ['unmod', 'context']:
 
                            nextline = lineiter.next()
 
                            if nextline['action'] in ['unmod', 'context'] or \
 
                               nextline['action'] == line['action']:
 
                                continue
 
                            self.differ(line, nextline)
 
                except StopIteration:
 
                    pass
 

	
 
        return diff_container(sorted(_files, key=sorter))
 

	
 
    def _parse_udiff(self, inline_diff=True):
 
        raise NotImplementedError()
 

	
 
    def _parse_lines(self, diff):
 
        """
 
        Parse the diff an return data for the template.
 
        """
 
        lineiter = self.lines
 

	
 
        files = []
 
        lineiter = iter(diff)
 
        stats = [0, 0]
 

	
 
        try:
 
            line = lineiter.next()
 
            while 1:
 
                # continue until we found the old file
 
                if not line.startswith('--- '):
 
                    line = lineiter.next()
 
                    continue
 

	
 
                chunks = []
 
                stats = [0, 0]
 
                operation, filename, old_rev, new_rev = \
 
                    self._extract_rev(line, lineiter.next())
 
                files.append({
 
                    'filename':         filename,
 
                    'old_revision':     old_rev,
 
                    'new_revision':     new_rev,
 
                    'chunks':           chunks,
 
                    'operation':        operation,
 
                    'stats':            stats,
 
                })
 

	
 
                line = lineiter.next()
 

	
 
                while line:
 
                lines = []
 
                chunks.append(lines)
 

	
 
                    match = self._chunk_re.match(line)
 

	
 
                    if not match:
 
                        break
 

	
 
                    lines = []
 
                    chunks.append(lines)
 

	
 
                    old_line, old_end, new_line, new_end = \
 
                        [int(x or 1) for x in match.groups()[:-1]]
 
                gr = match.groups()
 
                (old_line, old_end,
 
                 new_line, new_end) = [int(x or 1) for x in gr[:-1]]
 
                    old_line -= 1
 
                    new_line -= 1
 
                    gr = match.groups()
 

	
 
                    context = len(gr) == 5
 
                    old_end += old_line
 
                    new_end += new_line
 

	
 
                    if context:
 
                        # skip context only if it's first line
 
                        if int(gr[0]) > 1:
 
                            lines.append({
 
                                'old_lineno': '...',
 
                                'new_lineno': '...',
 
                                'action':     'context',
 
                                'line':       line,
 
                            })
 

	
 
                    line = lineiter.next()
 

	
 
                    while old_line < old_end or new_line < new_end:
 
                        if line:
 
                            command = line[0]
 
                            if command in ['+', '-', ' ']:
 
                                #only modify the line if it's actually a diff
 
                                # thing
 
                                line = line[1:]
 
                        else:
 
                            command = ' '
 

	
 
                        affects_old = affects_new = False
 

	
 
                        # ignore those if we don't expect them
 
                        if command in '#@':
 
                            continue
 
                        elif command == '+':
 
                            affects_new = True
 
                            action = 'add'
 
                            stats[0] += 1
 
                        elif command == '-':
 
                            affects_old = True
 
                            action = 'del'
 
                            stats[1] += 1
 
                        else:
 
                            affects_old = affects_new = True
 
                            action = 'unmod'
 

	
 
                        if line != self._newline_marker:
 
                            old_line += affects_old
 
                            new_line += affects_new
 
                            lines.append({
 
                                'old_lineno':   affects_old and old_line or '',
 
                                'new_lineno':   affects_new and new_line or '',
 
                                'action':       action,
 
                                'line':         line
 
                            })
 

	
 
                        line = lineiter.next()
 

	
 
                        if line == self._newline_marker:
 
                            # we need to append to lines, since this is not
 
                            # counted in the line specs of diff
 
                            lines.append({
 
                                'old_lineno':   '...',
 
                                'new_lineno':   '...',
 
                                'action':       'context',
 
                                'line':         line
 
                            })
 

	
 
        except StopIteration:
 
            pass
 

	
 
        sorter = lambda info: {'A': 0, 'M': 1, 'D': 2}.get(info['operation'])
 
        if inline_diff is False:
 
            return sorted(files, key=sorter)
 

	
 
        # highlight inline changes
 
        for diff_data in files:
 
            for chunk in diff_data['chunks']:
 
                lineiter = iter(chunk)
 
                try:
 
                    while 1:
 
                        line = lineiter.next()
 
                        if line['action'] not in ['unmod', 'context']:
 
                            nextline = lineiter.next()
 
                            if nextline['action'] in ['unmod', 'context'] or \
 
                               nextline['action'] == line['action']:
 
                                continue
 
                            self.differ(line, nextline)
 
                except StopIteration:
 
                    pass
 

	
 
        return sorted(files, key=sorter)
 

	
 
    def prepare(self, inline_diff=True):
 
        """
 
        Prepare the passed udiff for HTML rendering. It'l return a list
 
        of dicts
 
        """
 
        return self._parse_udiff(inline_diff=inline_diff)
 
        return chunks, stats
 

	
 
    def _safe_id(self, idstring):
 
        """Make a string safe for including in an id attribute.
 

	
 
        The HTML spec says that id attributes 'must begin with
 
        a letter ([A-Za-z]) and may be followed by any number
 
        of letters, digits ([0-9]), hyphens ("-"), underscores
 
        ("_"), colons (":"), and periods (".")'. These regexps
 
        are slightly over-zealous, in that they remove colons
 
        and periods unnecessarily.
 

	
 
        Whitespace is transformed into underscores, and then
 
        anything which is not a hyphen or a character that
 
        matches \w (alphanumerics and underscore) is removed.
 

	
 
        """
 
        # Transform all whitespace to underscore
 
        idstring = re.sub(r'\s', "_", '%s' % idstring)
 
        # Remove everything that is not a hyphen or a member of \w
 
        idstring = re.sub(r'(?!-)\W', "", idstring).lower()
 
        return idstring
 

	
 
    def raw_diff(self):
 
    def prepare(self, inline_diff=True):
 
        """
 
        Prepare the passed udiff for HTML rendering. It'l return a list
 
        of dicts with diff information
 
        """
 
        parsed = self._parser(inline_diff=inline_diff)
 
        self.parsed = True
 
        self.parsed_diff = parsed
 
        return parsed
 

	
 
    def as_raw(self, diff_lines=None):
 
        """
 
        Returns raw string as udiff
 
        """
 
        udiff_copy = self.copy_iterator()
 
        if self.__format == 'gitdiff':
 
            udiff_copy = self._parse_gitdiff(udiff_copy)
 
        return u''.join(udiff_copy)
 
        return u''.join(imap(self._line_counter, self._diff.splitlines(1)))
 

	
 
    def as_html(self, table_class='code-difftable', line_class='line',
 
                new_lineno_class='lineno old', old_lineno_class='lineno new',
 
                code_class='code', enable_comments=False, diff_lines=None):
 
                code_class='code', enable_comments=False, parsed_lines=None):
 
        """
 
        Return given diff as html table with customized css classes
 
        """
 
        def _link_to_if(condition, label, url):
 
            """
 
            Generates a link if condition is meet or just the label if not.
 
            """
 

	
 
            if condition:
 
                return '''<a href="%(url)s">%(label)s</a>''' % {
 
                    'url': url,
 
                    'label': label
 
                }
 
            else:
 
                return label
 
        if diff_lines is None:
 
            diff_lines = self.prepare()
 
        if not self.parsed:
 
            self.prepare()
 

	
 
        diff_lines = self.parsed_diff
 
        if parsed_lines:
 
            diff_lines = parsed_lines
 

	
 
        _html_empty = True
 
        _html = []
 
        _html.append('''<table class="%(table_class)s">\n''' % {
 
            'table_class': table_class
 
        })
 

	
 
        for diff in diff_lines:
 
            for line in diff['chunks']:
 
                _html_empty = False
 
                for change in line:
 
                    _html.append('''<tr class="%(lc)s %(action)s">\n''' % {
 
                        'lc': line_class,
 
                        'action': change['action']
 
                    })
 
                    anchor_old_id = ''
 
                    anchor_new_id = ''
 
                    anchor_old = "%(filename)s_o%(oldline_no)s" % {
 
                        'filename': self._safe_id(diff['filename']),
 
                        'oldline_no': change['old_lineno']
 
                    }
 
                    anchor_new = "%(filename)s_n%(oldline_no)s" % {
 
                        'filename': self._safe_id(diff['filename']),
 
                        'oldline_no': change['new_lineno']
 
                    }
 
                    cond_old = (change['old_lineno'] != '...' and
 
                                change['old_lineno'])
 
                    cond_new = (change['new_lineno'] != '...' and
 
                                change['new_lineno'])
 
                    if cond_old:
 
                        anchor_old_id = 'id="%s"' % anchor_old
 
                    if cond_new:
 
                        anchor_new_id = 'id="%s"' % anchor_new
 
                    ###########################################################
 
                    # OLD LINE NUMBER
 
                    ###########################################################
 
                    _html.append('''\t<td %(a_id)s class="%(olc)s">''' % {
 
                        'a_id': anchor_old_id,
 
                        'olc': old_lineno_class
 
                    })
 

	
 
                    _html.append('''%(link)s''' % {
 
                        'link': _link_to_if(True, change['old_lineno'],
 
                                            '#%s' % anchor_old)
 
                    })
 
                    _html.append('''</td>\n''')
 
                    ###########################################################
 
                    # NEW LINE NUMBER
 
                    ###########################################################
 

	
 
                    _html.append('''\t<td %(a_id)s class="%(nlc)s">''' % {
 
                        'a_id': anchor_new_id,
 
                        'nlc': new_lineno_class
 
                    })
 

	
 
                    _html.append('''%(link)s''' % {
 
                        'link': _link_to_if(True, change['new_lineno'],
 
                                            '#%s' % anchor_new)
 
                    })
 
                    _html.append('''</td>\n''')
 
                    ###########################################################
 
                    # CODE
 
                    ###########################################################
 
                    comments = '' if enable_comments else 'no-comment'
 
                    _html.append('''\t<td class="%(cc)s %(inc)s">''' % {
 
                        'cc': code_class,
 
                        'inc': comments
 
                    })
 
                    _html.append('''\n\t\t<pre>%(code)s</pre>\n''' % {
 
                        'code': change['line']
 
                    })
 

	
 
                    _html.append('''\t</td>''')
 
                    _html.append('''\n</tr>\n''')
 
        _html.append('''</table>''')
 
        if _html_empty:
 
            return None
 
        return ''.join(_html)
 

	
 
    def stat(self):
 
        """
 
        Returns tuple of added, and removed lines for this instance
 
        """
 
        return self.adds, self.removes
 

	
 

	
 
class InMemoryBundleRepo(bundlerepository):
 
    def __init__(self, ui, path, bundlestream):
 
        self._tempparent = None
 
        localrepo.localrepository.__init__(self, ui, path)
 
        self.ui.setconfig('phases', 'publish', False)
 

	
 
        self.bundle = bundlestream
 

	
 
        # dict with the mapping 'filename' -> position in the bundle
 
        self.bundlefilespos = {}
 

	
 

	
 
def differ(org_repo, org_ref, other_repo, other_ref, discovery_data=None,
 
           bundle_compare=False):
 
           bundle_compare=False, context=3, ignore_whitespace=False):
 
    """
 
    General differ between branches, bookmarks or separate but releated
 
    General differ between branches, bookmarks, revisions of two remote related
 
    repositories
 

	
 
    :param org_repo:
 
    :type org_repo:
 
    :param org_ref:
 
    :type org_ref:
 
    :param other_repo:
 
    :type other_repo:
 
    :param other_ref:
 
    :type other_ref:
 
    """
 

	
 
    bundlerepo = None
 
    ignore_whitespace = False
 
    context = 3
 
    ignore_whitespace = ignore_whitespace
 
    context = context
 
    org_repo = org_repo.scm_instance._repo
 
    other_repo = other_repo.scm_instance._repo
 
    opts = diffopts(git=True, ignorews=ignore_whitespace, context=context)
 
    org_ref = org_ref[1]
 
    other_ref = other_ref[1]
 

	
 
    if org_repo != other_repo and bundle_compare:
 

	
 
        common, incoming, rheads = discovery_data
 
        other_repo_peer = localrepo.locallegacypeer(other_repo.local())
 
        # create a bundle (uncompressed if other repo is not local)
 
        if other_repo_peer.capable('getbundle') and incoming:
 
            # disable repo hooks here since it's just bundle !
 
            # patch and reset hooks section of UI config to not run any
 
            # hooks on fetching archives with subrepos
 
            for k, _ in other_repo.ui.configitems('hooks'):
 
                other_repo.ui.setconfig('hooks', k, None)
 

	
 
            unbundle = other_repo.getbundle('incoming', common=common,
 
                                            heads=None)
 

	
 
            buf = BytesIO()
 
            while True:
 
                chunk = unbundle._stream.read(1024 * 4)
 
                if not chunk:
 
                    break
 
                buf.write(chunk)
 

	
 
            buf.seek(0)
 
            # replace chunked _stream with data that can do tell() and seek()
 
            unbundle._stream = buf
 

	
 
            ui = make_ui('db')
 
            bundlerepo = InMemoryBundleRepo(ui, path=org_repo.root,
 
                                            bundlestream=unbundle)
 

	
 
        return ''.join(patch.diff(bundlerepo or org_repo,
 
                                  node1=org_repo[org_ref].node(),
 
                                  node2=other_repo[other_ref].node(),
 
                                  opts=opts))
 
    else:
 
        log.debug('running diff between %s@%s and %s@%s'
 
                  % (org_repo, org_ref, other_repo, other_ref))
 
        return ''.join(patch.diff(org_repo, node1=org_ref, node2=other_ref,
 
                                  opts=opts))
rhodecode/lib/helpers.py
Show inline comments
 
@@ -846,141 +846,148 @@ class RepoPage(Page):
 

	
 
def changed_tooltip(nodes):
 
    """
 
    Generates a html string for changed nodes in changeset page.
 
    It limits the output to 30 entries
 

	
 
    :param nodes: LazyNodesGenerator
 
    """
 
    if nodes:
 
        pref = ': <br/> '
 
        suf = ''
 
        if len(nodes) > 30:
 
            suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
 
        return literal(pref + '<br/> '.join([safe_unicode(x.path)
 
                                             for x in nodes[:30]]) + suf)
 
    else:
 
        return ': ' + _('No Files')
 

	
 

	
 
def repo_link(groups_and_repos):
 
    """
 
    Makes a breadcrumbs link to repo within a group
 
    joins &raquo; on each group to create a fancy link
 

	
 
    ex::
 
        group >> subgroup >> repo
 

	
 
    :param groups_and_repos:
 
    """
 
    groups, repo_name = groups_and_repos
 

	
 
    if not groups:
 
        return repo_name
 
    else:
 
        def make_link(group):
 
            return link_to(group.name, url('repos_group_home',
 
                                           group_name=group.group_name))
 
        return literal(' &raquo; '.join(map(make_link, groups)) + \
 
                       " &raquo; " + repo_name)
 

	
 

	
 
def fancy_file_stats(stats):
 
    """
 
    Displays a fancy two colored bar for number of added/deleted
 
    lines of code on file
 

	
 
    :param stats: two element list of added/deleted lines of code
 
    """
 

	
 
    a, d, t = stats[0], stats[1], stats[0] + stats[1]
 
    width = 100
 
    unit = float(width) / (t or 1)
 

	
 
    # needs > 9% of width to be visible or 0 to be hidden
 
    a_p = max(9, unit * a) if a > 0 else 0
 
    d_p = max(9, unit * d) if d > 0 else 0
 
    p_sum = a_p + d_p
 

	
 
    if p_sum > width:
 
        #adjust the percentage to be == 100% since we adjusted to 9
 
        if a_p > d_p:
 
            a_p = a_p - (p_sum - width)
 
        else:
 
            d_p = d_p - (p_sum - width)
 

	
 
    a_v = a if a > 0 else ''
 
    d_v = d if d > 0 else ''
 

	
 
    def cgen(l_type):
 
    def cgen(l_type, a_v, d_v):
 
        mapping = {'tr': 'top-right-rounded-corner-mid',
 
                   'tl': 'top-left-rounded-corner-mid',
 
                   'br': 'bottom-right-rounded-corner-mid',
 
                   'bl': 'bottom-left-rounded-corner-mid'}
 
        map_getter = lambda x: mapping[x]
 

	
 
        if l_type == 'a' and d_v:
 
            #case when added and deleted are present
 
            return ' '.join(map(map_getter, ['tl', 'bl']))
 

	
 
        if l_type == 'a' and not d_v:
 
            return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
 

	
 
        if l_type == 'd' and a_v:
 
            return ' '.join(map(map_getter, ['tr', 'br']))
 

	
 
        if l_type == 'd' and not a_v:
 
            return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
 

	
 
    a, d = stats[0], stats[1]
 
    width = 100
 

	
 
    if a == 'b':
 
        #binary mode
 
        b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin')
 
        b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin')
 
        return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
 

	
 
    t = stats[0] + stats[1]
 
    unit = float(width) / (t or 1)
 

	
 
    # needs > 9% of width to be visible or 0 to be hidden
 
    a_p = max(9, unit * a) if a > 0 else 0
 
    d_p = max(9, unit * d) if d > 0 else 0
 
    p_sum = a_p + d_p
 

	
 
    if p_sum > width:
 
        #adjust the percentage to be == 100% since we adjusted to 9
 
        if a_p > d_p:
 
            a_p = a_p - (p_sum - width)
 
        else:
 
            d_p = d_p - (p_sum - width)
 

	
 
    a_v = a if a > 0 else ''
 
    d_v = d if d > 0 else ''
 

	
 
    d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
 
        cgen('a'), a_p, a_v
 
        cgen('a', a_v, d_v), a_p, a_v
 
    )
 
    d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
 
        cgen('d'), d_p, d_v
 
        cgen('d', a_v, d_v), d_p, d_v
 
    )
 
    return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
 

	
 

	
 
def urlify_text(text_):
 

	
 
    url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
 
                         '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
 

	
 
    def url_func(match_obj):
 
        url_full = match_obj.groups()[0]
 
        return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
 

	
 
    return literal(url_pat.sub(url_func, text_))
 

	
 

	
 
def urlify_changesets(text_, repository):
 
    """
 
    Extract revision ids from changeset and make link from them
 

	
 
    :param text_:
 
    :param repository:
 
    """
 

	
 
    URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
 

	
 
    def url_func(match_obj):
 
        rev = match_obj.groups()[0]
 
        pref = ''
 
        if match_obj.group().startswith(' '):
 
            pref = ' '
 
        tmpl = (
 
        '%(pref)s<a class="%(cls)s" href="%(url)s">'
 
        '%(rev)s'
 
        '</a>'
 
        )
 
        return tmpl % {
 
         'pref': pref,
 
         'cls': 'revision-link',
 
         'url': url('changeset_home', repo_name=repository, revision=rev),
 
         'rev': rev,
 
        }
 

	
 
    newtext = URL_PAT.sub(url_func, text_)
 

	
 
    return newtext
 

	
 

	
rhodecode/lib/vcs/backends/base.py
Show inline comments
 
@@ -889,84 +889,84 @@ class BaseInMemoryChangeset(object):
 
        if self.removed and not parents:
 
            raise NodeDoesNotExistError("Cannot remove node at %s as there "
 
                "were no parents specified" % self.removed[0].path)
 
        really_removed = set()
 
        for p in parents:
 
            for node in self.removed:
 
                try:
 
                    p.get_node(node.path)
 
                    really_removed.add(node)
 
                except ChangesetError:
 
                    pass
 
        not_removed = set(self.removed) - really_removed
 
        if not_removed:
 
            raise NodeDoesNotExistError("Cannot remove node at %s from "
 
                "following parents: %s" % (not_removed[0], parents))
 

	
 
    def commit(self, message, author, parents=None, branch=None, date=None,
 
            **kwargs):
 
        """
 
        Performs in-memory commit (doesn't check workdir in any way) and
 
        returns newly created ``Changeset``. Updates repository's
 
        ``revisions``.
 

	
 
        .. note::
 
            While overriding this method each backend's should call
 
            ``self.check_integrity(parents)`` in the first place.
 

	
 
        :param message: message of the commit
 
        :param author: full username, i.e. "Joe Doe <joe.doe@example.com>"
 
        :param parents: single parent or sequence of parents from which commit
 
          would be derieved
 
        :param date: ``datetime.datetime`` instance. Defaults to
 
          ``datetime.datetime.now()``.
 
        :param branch: branch name, as string. If none given, default backend's
 
          branch would be used.
 

	
 
        :raises ``CommitError``: if any error occurs while committing
 
        """
 
        raise NotImplementedError
 

	
 

	
 
class EmptyChangeset(BaseChangeset):
 
    """
 
    An dummy empty changeset. It's possible to pass hash when creating
 
    an EmptyChangeset
 
    """
 

	
 
    def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
 
                 alias=None, message='', author='', date=''):
 
                 alias=None, revision=-1, message='', author='', date=''):
 
        self._empty_cs = cs
 
        self.revision = -1
 
        self.revision = revision
 
        self.message = message
 
        self.author = author
 
        self.date = date
 
        self.repository = repo
 
        self.requested_revision = requested_revision
 
        self.alias = alias
 

	
 
    @LazyProperty
 
    def raw_id(self):
 
        """
 
        Returns raw string identifying this changeset, useful for web
 
        representation.
 
        """
 

	
 
        return self._empty_cs
 

	
 
    @LazyProperty
 
    def branch(self):
 
        from rhodecode.lib.vcs.backends import get_backend
 
        return get_backend(self.alias).DEFAULT_BRANCH_NAME
 

	
 
    @LazyProperty
 
    def short_id(self):
 
        return self.raw_id[:12]
 

	
 
    def get_file_changeset(self, path):
 
        return self
 

	
 
    def get_file_content(self, path):
 
        return u''
 

	
 
    def get_file_size(self, path):
 
        return 0
rhodecode/lib/vcs/backends/git/repository.py
Show inline comments
 
@@ -475,116 +475,117 @@ class GitRepository(BaseRepository):
 
        else:
 
            cmd_template += ' --all'
 

	
 
        cmd = Template(cmd_template).safe_substitute(**cmd_params)
 
        revs = self.run_git_command(cmd)[0].splitlines()
 
        start_pos = 0
 
        end_pos = len(revs)
 
        if start:
 
            _start = self._get_revision(start)
 
            try:
 
                start_pos = revs.index(_start)
 
            except ValueError:
 
                pass
 

	
 
        if end is not None:
 
            _end = self._get_revision(end)
 
            try:
 
                end_pos = revs.index(_end)
 
            except ValueError:
 
                pass
 

	
 
        if None not in [start, end] and start_pos > end_pos:
 
            raise RepositoryError('start cannot be after end')
 

	
 
        if end_pos is not None:
 
            end_pos += 1
 

	
 
        revs = revs[start_pos:end_pos]
 
        if reverse:
 
            revs = reversed(revs)
 
        for rev in revs:
 
            yield self.get_changeset(rev)
 

	
 
    def get_diff(self, rev1, rev2, path=None, ignore_whitespace=False,
 
                 context=3):
 
        """
 
        Returns (git like) *diff*, as plain text. Shows changes introduced by
 
        ``rev2`` since ``rev1``.
 

	
 
        :param rev1: Entry point from which diff is shown. Can be
 
          ``self.EMPTY_CHANGESET`` - in this case, patch showing all
 
          the changes since empty state of the repository until ``rev2``
 
        :param rev2: Until which revision changes should be shown.
 
        :param ignore_whitespace: If set to ``True``, would not show whitespace
 
          changes. Defaults to ``False``.
 
        :param context: How many lines before/after changed lines should be
 
          shown. Defaults to ``3``.
 
        """
 
        flags = ['-U%s' % context]
 
        flags = ['-U%s' % context, '--full-index', '--binary', '-p', '-M', '--abbrev=40']
 
        if ignore_whitespace:
 
            flags.append('-w')
 

	
 
        if hasattr(rev1, 'raw_id'):
 
            rev1 = getattr(rev1, 'raw_id')
 

	
 
        if hasattr(rev2, 'raw_id'):
 
            rev2 = getattr(rev2, 'raw_id')
 

	
 
        if rev1 == self.EMPTY_CHANGESET:
 
            rev2 = self.get_changeset(rev2).raw_id
 
            cmd = ' '.join(['show'] + flags + [rev2])
 
        else:
 
            rev1 = self.get_changeset(rev1).raw_id
 
            rev2 = self.get_changeset(rev2).raw_id
 
            cmd = ' '.join(['diff'] + flags + [rev1, rev2])
 

	
 
        if path:
 
            cmd += ' -- "%s"' % path
 

	
 
        stdout, stderr = self.run_git_command(cmd)
 
        # If we used 'show' command, strip first few lines (until actual diff
 
        # starts)
 
        if rev1 == self.EMPTY_CHANGESET:
 
            lines = stdout.splitlines()
 
            x = 0
 
            for line in lines:
 
                if line.startswith('diff'):
 
                    break
 
                x += 1
 
            # Append new line just like 'diff' command do
 
            stdout = '\n'.join(lines[x:]) + '\n'
 
        return stdout
 

	
 
    @LazyProperty
 
    def in_memory_changeset(self):
 
        """
 
        Returns ``GitInMemoryChangeset`` object for this repository.
 
        """
 
        return GitInMemoryChangeset(self)
 

	
 
    def clone(self, url, update_after_clone=True, bare=False):
 
        """
 
        Tries to clone changes from external location.
 

	
 
        :param update_after_clone: If set to ``False``, git won't checkout
 
          working directory
 
        :param bare: If set to ``True``, repository would be cloned into
 
          *bare* git repository (no working directory at all).
 
        """
 
        url = self._get_url(url)
 
        cmd = ['clone']
 
        if bare:
 
            cmd.append('--bare')
 
        elif not update_after_clone:
 
            cmd.append('--no-checkout')
 
        cmd += ['--', '"%s"' % url, '"%s"' % self.path]
 
        cmd = ' '.join(cmd)
 
        # If error occurs run_git_command raises RepositoryError already
 
        self.run_git_command(cmd)
 

	
 
    def pull(self, url):
 
        """
 
        Tries to pull changes from external location.
 
        """
 
        url = self._get_url(url)
 
        cmd = ['pull']
 
        cmd.append("--ff-only")
rhodecode/lib/vcs/backends/hg/repository.py
Show inline comments
 
@@ -197,98 +197,101 @@ class MercurialRepository(BaseRepository
 
            raise RepositoryError(e.message)
 

	
 
    @LazyProperty
 
    def bookmarks(self):
 
        """
 
        Get's bookmarks for this repository
 
        """
 
        return self._get_bookmarks()
 

	
 
    def _get_bookmarks(self):
 
        if self._empty:
 
            return {}
 

	
 
        sortkey = lambda ctx: ctx[0]  # sort by name
 
        _bookmarks = [(safe_unicode(n), hex(h),) for n, h in
 
                 self._repo._bookmarks.items()]
 
        return OrderedDict(sorted(_bookmarks, key=sortkey, reverse=True))
 

	
 
    def _get_all_revisions(self):
 

	
 
        return map(lambda x: hex(x[7]), self._repo.changelog.index)[:-1]
 

	
 
    def get_diff(self, rev1, rev2, path='', ignore_whitespace=False,
 
                  context=3):
 
        """
 
        Returns (git like) *diff*, as plain text. Shows changes introduced by
 
        ``rev2`` since ``rev1``.
 

	
 
        :param rev1: Entry point from which diff is shown. Can be
 
          ``self.EMPTY_CHANGESET`` - in this case, patch showing all
 
          the changes since empty state of the repository until ``rev2``
 
        :param rev2: Until which revision changes should be shown.
 
        :param ignore_whitespace: If set to ``True``, would not show whitespace
 
          changes. Defaults to ``False``.
 
        :param context: How many lines before/after changed lines should be
 
          shown. Defaults to ``3``.
 
        """
 
        if hasattr(rev1, 'raw_id'):
 
            rev1 = getattr(rev1, 'raw_id')
 

	
 
        if hasattr(rev2, 'raw_id'):
 
            rev2 = getattr(rev2, 'raw_id')
 

	
 
        # Check if given revisions are present at repository (may raise
 
        # ChangesetDoesNotExistError)
 
        if rev1 != self.EMPTY_CHANGESET:
 
            self.get_changeset(rev1)
 
        self.get_changeset(rev2)
 
        if path:
 
            file_filter = match(self.path, '', [path])
 
        else:
 
            file_filter = None
 

	
 
        file_filter = match(self.path, '', [path])
 
        return ''.join(patch.diff(self._repo, rev1, rev2, match=file_filter,
 
                          opts=diffopts(git=True,
 
                                        ignorews=ignore_whitespace,
 
                                        context=context)))
 

	
 
    @classmethod
 
    def _check_url(cls, url):
 
        """
 
        Function will check given url and try to verify if it's a valid
 
        link. Sometimes it may happened that mercurial will issue basic
 
        auth request that can cause whole API to hang when used from python
 
        or other external calls.
 

	
 
        On failures it'll raise urllib2.HTTPError, return code 200 if url
 
        is valid or True if it's a local path
 
        """
 

	
 
        from mercurial.util import url as Url
 

	
 
        # those authnadlers are patched for python 2.6.5 bug an
 
        # infinit looping when given invalid resources
 
        from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
 

	
 
        # check first if it's not an local url
 
        if os.path.isdir(url) or url.startswith('file:'):
 
            return True
 

	
 
        if('+' in url[:url.find('://')]):
 
            url = url[url.find('+') + 1:]
 

	
 
        handlers = []
 
        test_uri, authinfo = Url(url).authinfo()
 

	
 
        if authinfo:
 
            #create a password manager
 
            passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
 
            passmgr.add_password(*authinfo)
 

	
 
            handlers.extend((httpbasicauthhandler(passmgr),
 
                             httpdigestauthhandler(passmgr)))
 

	
 
        o = urllib2.build_opener(*handlers)
 
        o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
 
                        ('Accept', 'application/mercurial-0.1')]
 

	
 
        q = {"cmd": 'between'}
 
        q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
 
        qs = '?%s' % urllib.urlencode(q)
rhodecode/public/css/style.css
Show inline comments
 
@@ -2461,96 +2461,132 @@ h3.files_location {
 
}
 
 
#changeset_compare_view_content .compare_view_commits td {
 
	padding: 0px 0px 0px 12px !important;
 
}
 
 
#changeset_content .container .right {
 
	float: right;
 
	width: 20%;
 
	text-align: right;
 
}
 
 
#changeset_content .container .left .message {
 
	white-space: pre-wrap;
 
}
 
#changeset_content .container .left .message a:hover {
 
	text-decoration: none;
 
}
 
.cs_files .cur_cs {
 
	margin: 10px 2px;
 
	font-weight: bold;
 
}
 
 
.cs_files .node {
 
	float: left;
 
}
 
 
.cs_files .changes {
 
	float: right;
 
	color:#003367;
 
	
 
}
 
 
.cs_files .changes .added {
 
	background-color: #BBFFBB;
 
	float: left;
 
	text-align: center;
 
	font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
.cs_files .changes .deleted {
 
	background-color: #FF8888;
 
	float: left;
 
	text-align: center;
 
	font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
/*new binary*/
 
.cs_files .changes .bin1 {
 
    background-color: #BBFFBB;
 
    float: left;
 
    text-align: center;
 
    font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
/*deleted binary*/
 
.cs_files .changes .bin2 {
 
    background-color: #FF8888;
 
    float: left;
 
    text-align: center;
 
    font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
/*mod binary*/
 
.cs_files .changes .bin3 {
 
    background-color: #DDDDDD;
 
    float: left;
 
    text-align: center;
 
    font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
/*rename file*/
 
.cs_files .changes .bin4 {
 
    background-color: #6D99FF;
 
    float: left;
 
    text-align: center;
 
    font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
 
.cs_files .cs_added,.cs_files .cs_A {
 
	background: url("../images/icons/page_white_add.png") no-repeat scroll
 
		3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	margin-top: 7px;
 
	text-align: left;
 
}
 
 
.cs_files .cs_changed,.cs_files .cs_M {
 
	background: url("../images/icons/page_white_edit.png") no-repeat scroll
 
		3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	margin-top: 7px;
 
	text-align: left;
 
}
 
 
.cs_files .cs_removed,.cs_files .cs_D {
 
	background: url("../images/icons/page_white_delete.png") no-repeat
 
		scroll 3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	margin-top: 7px;
 
	text-align: left;
 
}
 
 
#graph {
 
	overflow: hidden;
 
}
 
 
#graph_nodes {
 
	float: left;
 
	margin-right: 0px;
 
	margin-top: 0px;
 
}
 
 
#graph_content {
 
	width: 80%;
 
	float: left;
 
}
 
 
#graph_content .container_header {
 
	border-bottom: 1px solid #DDD;
 
	padding: 10px;
 
	height: 25px;
 
}
rhodecode/templates/changeset/changeset.html
Show inline comments
 
## -*- coding: utf-8 -*-
 

	
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('%s Changeset') % c.repo_name} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_(u'Home'),h.url('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('Changeset')} - <span class='hash'>r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}</span>
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('changelog')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <script>
 
    var _USERS_AC_DATA = ${c.users_array|n};
 
    var _GROUPS_AC_DATA = ${c.users_groups_array|n};
 
    AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}";
 
    AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
 
    </script>
 
    <div class="table">
 
		<div class="diffblock">
 
			<div class="code-header">
 
                <div class="hash">
 
                 r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
 
                </div>
 
                <div class="date">
 
                  ${h.fmt_date(c.changeset.date)}
 
                </div>
 
                <div class="changeset-status-container">
 
                    %if c.statuses:
 
                      <div title="${_('Changeset status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.statuses[0])}]</div>
 
                      <div class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[0])}" /></div>
 
                    %endif
 
                </div>
 
                <div class="diff-actions">
 
                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show')}"  class="tooltip" title="${h.tooltip(_('raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
 
                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='raw')}"  class="tooltip" title="${h.tooltip(_('raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
 
                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download')}"  class="tooltip" title="${h.tooltip(_('download diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
 
                  ${c.ignorews_url(request.GET)}
 
                  ${c.context_url(request.GET)}
 
                </div>
 
                <div class="comments-number" style="float:right;padding-right:5px">${ungettext("%d comment", "%d comments", len(c.comments)) % len(c.comments)} ${ungettext("(%d inline)", "(%d inline)", c.inline_cnt) % c.inline_cnt}</div>
 
			</div>
 
		</div>
 
	    <div id="changeset_content">
 
			<div class="container">
 
	             <div class="left">
 
	                 <div class="author">
 
	                     <div class="gravatar">
 
	                         <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.changeset.author),20)}"/>
 
	                     </div>
 
	                     <span>${h.person(c.changeset.author)}</span><br/>
 
	                     <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
 
	                 </div>
 
	                 <div class="message">${h.urlify_commit(c.changeset.message, c.repo_name)}</div>
 
	             </div>
 
	             <div class="right">
 
		             <div class="changes">
 
                        % if len(c.changeset.affected_files) <= c.affected_files_cut_off:
 
		                 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
 
		                 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
 
		                 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
 
	                    % else:
 
                         <span class="removed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
 
                         <span class="changed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
 
                         <span class="added"   title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
 
	                    % endif
 
		             </div>
 

	
 
		            %if c.changeset.parents:
 
		             %for p_cs in reversed(c.changeset.parents):
 
		                 <div class="parent">${_('Parent')}
 
                     <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
 
		                     h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
 
		                 </div>
 
		             %endfor
 
                    %else:
 
                        <div class="parent">${_('No parents')}</div>
 
                    %endif
 
		         <span class="logtags">
 
                 %if len(c.changeset.parents)>1:
 
                 <span class="merge">${_('merge')}</span>
 
                 %endif
 
		             %if c.changeset.branch:
 
                     <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
 
		             ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}
 
                     </span>
 
                     %endif
 
		             %for tag in c.changeset.tags:
 
		                 <span class="tagtag"  title="${'%s %s' % (_('tag'),tag)}">
 
		                 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
 
		             %endfor
 
		         </span>
 
	                </div>
 
	        </div>
 
	        <span>
 
            % if c.limited_diff:
 
            ${_('%s files affected:') % (len(c.changeset.affected_files))}
 
            % else:
 
	        ${_('%s files affected with %s insertions and %s deletions:') % (len(c.changeset.affected_files),c.lines_added,c.lines_deleted)}
 
	        %endif
 
	        </span>
 
	        <div class="cs_files">
 
	                %for change,filenode,diff,cs1,cs2,stat in c.changes:
 
              %for FID, (cs1, cs2, change, path, diff, stats) in c.changes[c.changeset.raw_id].iteritems():
 
	                    <div class="cs_${change}">
 
                            <div class="node">
 
                            %if change != 'removed':
 
                                ${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path,request.GET)+"_target")}
 
                            %else:
 
                                ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID('',filenode.path)))}
 
                            %endif
 
                            <a href="#${FID}">${h.safe_unicode(path)}</a>
 
                            </div>
 
		                    <div class="changes">${h.fancy_file_stats(stat)}</div>
 
                    <div class="changes">${h.fancy_file_stats(stats)}</div>
 
	                    </div>
 
	                %endfor
 
	                % if c.cut_off:
 
	                  ${_('Changeset was too big and was cut off...')}
 
              % if c.limited_diff:
 
                <h5>${_('Changeset was too big and was cut off...')}</h5>
 
	                % endif
 
	        </div>
 
	    </div>
 

	
 
    </div>
 
    <script>
 
    var _USERS_AC_DATA = ${c.users_array|n};
 
    var _GROUPS_AC_DATA = ${c.users_groups_array|n};
 
    AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}";
 
    AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
 
    </script>
 

	
 
    ## diff block
 
    <%namespace name="diff_block" file="/changeset/diff_block.html"/>
 
    ${diff_block.diff_block(c.changes)}
 
    ${diff_block.diff_block(c.changes[c.changeset.raw_id])}
 

	
 
    % if c.limited_diff:
 
      <h4>${_('Changeset was too big and was cut off...')}</h4>
 
    % endif
 

	
 
    ## template for inline comment form
 
    <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 
    ${comment.comment_inline_form()}
 

	
 
    ## render comments and inlines
 
    ${comment.generate_comments()}
 

	
 
    ## main comment form and it status
 
    ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id),
 
                       h.changeset_status(c.rhodecode_db_repo, c.changeset.raw_id))}
 

	
 
    ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
 
    <script type="text/javascript">
 
      YUE.onDOMReady(function(){
 
          YUE.on(YUQ('.show-inline-comments'),'change',function(e){
 
              var show = 'none';
 
              var target = e.currentTarget;
 
              if(target == null){
 
                  target = this;
 
              }
 
              if(target.checked){
 
                  var show = ''
 
              }
 
              var boxid = YUD.getAttribute(target,'id_for');
 
              var comments = YUQ('#{0} .inline-comments'.format(boxid));
 
              for(c in comments){
 
                 YUD.setStyle(comments[c],'display',show);
 
              }
 
              var btns = YUQ('#{0} .inline-comments-button'.format(boxid));
 
              for(c in btns){
 
                  YUD.setStyle(btns[c],'display',show);
 
               }
 
          })
 

	
 
          YUE.on(YUQ('.line'),'click',function(e){
 
              var tr = e.currentTarget;
 
              if(tr == null){
 
                  tr = this;
 
              }
 
              injectInlineForm(tr);
 
          });
 

	
 
          // inject comments into they proper positions
 
          var file_comments = YUQ('.inline-comment-placeholder');
 
          renderInlineComments(file_comments);
 
      })
 

	
rhodecode/templates/changeset/changeset_range.html
Show inline comments
 
@@ -10,98 +10,98 @@
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('changelog')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <div class="table">
 
		<div id="body" class="diffblock">
 
			<div class="code-header cv">
 
		        <h3 class="code-header-title">${_('Compare View')}</h3>
 
                <div>
 
				${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
 
				</div>
 
			</div>
 
		</div>
 
	    <div id="changeset_compare_view_content">
 
			<div class="container">
 
			<table class="compare_view_commits noborder">
 
            %for cnt,cs in enumerate(c.cs_ranges):
 
                <tr>
 
                <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td>
 
                <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
 
                <td><div class="author">${h.person(cs.author)}</div></td>
 
                <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
 
                <td>
 
                  %if c.statuses:
 
                    <div title="${h.tooltip(_('Changeset status'))}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cnt])}" /></div>
 
                  %endif
 
                </td>
 
                <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td>
 
                </tr>
 
            %endfor
 
            </table>
 
	        </div>
 
	        <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
 
	        <div class="cs_files">
 
	               %for cs in c.cs_ranges:
 
	                   <div class="cur_cs">${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
 
	                %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]:
 
	                    <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div>
 
	                  %for FID, (cs1, cs2, change, path, diff, stats) in c.changes[cs.raw_id].iteritems():
 
	                    <div class="cs_${change}">${h.link_to(h.safe_unicode(path),h.url.current(anchor=FID))}</div>
 
	                %endfor
 
	               %endfor
 
	        </div>
 
	    </div>
 

	
 
    </div>
 
    <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 
    <%namespace name="diff_block" file="/changeset/diff_block.html"/>
 
     %for cs in c.cs_ranges:
 
          ##${comment.comment_inline_form(cs)}
 
          ## diff block
 
          <div class="h3">
 
          <a class="tooltip" title="${h.tooltip(cs.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</a>
 
             <div class="gravatar">
 
                 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),20)}"/>
 
             </div>
 
             <div class="right">
 
              <span class="logtags">
 
                %if len(cs.parents)>1:
 
                <span class="merge">${_('merge')}</span>
 
                %endif
 
                %if cs.branch:
 
                <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
 
                   ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
 
                </span>
 
                %endif
 
                %if h.is_hg(c.rhodecode_repo):
 
                  %for book in cs.bookmarks:
 
                  <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
 
                     ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
 
                  </span>
 
                  %endfor
 
                %endif
 
                %for tag in cs.tags:
 
                    <span class="tagtag"  title="${'%s %s' % (_('tag'),tag)}">
 
                    ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
 
                %endfor
 
              </span>
 
            </div>
 
           </div>
 
          ${diff_block.diff_block(c.changes[cs.raw_id])}
 
          ##${comment.comments(cs)}
 

	
 
     %endfor
 
     <script type="text/javascript">
 

	
 
      YUE.onDOMReady(function(){
 

	
rhodecode/templates/changeset/diff_block.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
##usage:
 
## <%namespace name="diff_block" file="/changeset/diff_block.html"/>
 
## ${diff_block.diff_block(change)}
 
##
 
<%def name="diff_block(change)">
 

	
 
%for op,filenode,diff,cs1,cs2,stat in change:
 
    %if op !='removed':
 
    <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}_target" style="clear:both;margin-top:25px"></div>
 
    <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}" class="diffblock  margined comm">
 
%for FID,(cs1, cs2, change, path, diff, stats) in change.iteritems():
 
    ##%if op !='removed':
 
    <div id="${FID}_target" style="clear:both;margin-top:25px"></div>
 
    <div id="${FID}" class="diffblock  margined comm">
 
        <div class="code-header">
 
            <div class="changeset_header">
 
                <div class="changeset_file">
 
                    ${h.link_to_if(change!='removed',h.safe_unicode(filenode.path),h.url('files_home',repo_name=c.repo_name,
 
                    revision=filenode.changeset.raw_id,f_path=h.safe_unicode(filenode.path)))}
 
                    ${h.link_to_if(change!='removed',h.safe_unicode(path),h.url('files_home',repo_name=c.repo_name,
 
                    revision=cs2,f_path=h.safe_unicode(path)))}
 
                </div>
 
                <div class="diff-actions">
 
                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${h.tooltip(_('diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_go.png')}"/></a>
 
                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw')}" class="tooltip" title="${h.tooltip(_('raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
 
                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download')}" class="tooltip" title="${h.tooltip(_('download diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
 
                  ${c.ignorews_url(request.GET, h.FID(filenode.changeset.raw_id,filenode.path))}
 
                  ${c.context_url(request.GET, h.FID(filenode.changeset.raw_id,filenode.path))}
 
                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${h.tooltip(_('diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_go.png')}"/></a>
 
                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='raw')}" class="tooltip" title="${h.tooltip(_('raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
 
                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='download')}" class="tooltip" title="${h.tooltip(_('download diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
 
                  ${c.ignorews_url(request.GET, h.FID(cs2,path))}
 
                  ${c.context_url(request.GET, h.FID(cs2,path))}
 
                </div>
 
                <span style="float:right;margin-top:-3px">
 
                  <label>
 
                  ${_('show inline comments')}
 
                  ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=h.FID(filenode.changeset.raw_id,filenode.path))}
 
                  ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=h.FID(cs2,path))}
 
                  </label>
 
                </span>
 
            </div>
 
        </div>
 
        <div class="code-body">
 
            <div class="full_f_path" path="${h.safe_unicode(filenode.path)}"></div>
 
            <div class="full_f_path" path="${h.safe_unicode(path)}"></div>
 
            ${diff|n}
 
        </div>
 
    </div>
 
    %endif
 
    ##%endif
 
%endfor
 

	
 
</%def>
 

	
 
<%def name="diff_block_simple(change)">
 

	
 
  %for op,filenode_path,diff in change:
 
    <div id="${h.FID('',filenode_path)}_target" style="clear:both;margin-top:25px"></div>
 
    <div id="${h.FID('',filenode_path)}" class="diffblock  margined comm">
 
      <div class="code-header">
 
          <div class="changeset_header">
 
              <div class="changeset_file">
 
                  <a href="#">${h.safe_unicode(filenode_path)}</a>
 
              </div>
 
          </div>
 
      </div>
 
        <div class="code-body">
 
            <div class="full_f_path" path="${h.safe_unicode(filenode_path)}"></div>
 
            ${diff|n}
 
        </div>
 
    </div>
 
  %endfor
 
</%def>
rhodecode/templates/changeset/raw_changeset.html
Show inline comments
 
%if h.is_hg(c.scm_type):
 
# ${c.scm_type.upper()} changeset patch
 
%if h.is_hg(c.rhodecode_repo):
 
# ${c.rhodecode_repo.alias.upper()} changeset patch
 
# User ${c.changeset.author|n}
 
# Date ${c.changeset.date}
 
# Node ID ${c.changeset.raw_id}
 
${c.parent_tmpl}
 
${c.changeset.message}
 
%endif
 
${c.diffs|n}
 
%for FID, (cs1, cs2, change, path, diff, stats) in c.changes[c.changeset.raw_id].iteritems():
 
${diff|n}
 
%endfor
rhodecode/tests/fixtures/git_diff_binary_and_normal.diff
Show inline comments
 
new file 100644
 
diff --git a/img/baseline-10px.png b/img/baseline-10px.png
 
new file mode 100644
 
index 0000000000000000000000000000000000000000..16095dcbf5c9ea41caeb1e3e41d647d425222ed1
 
GIT binary patch
 
literal 152
 
zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)pi0lw^r(L`iUdT1k0gQ7VIDN`6wR
 
zf@f}GdTLN=VoGJ<$y6JlA}dc9$B>F!Nx%O8w`Ue+77%bXFxq5j_~-xsZV_1~1zCBH
 
y)y@U((_~Lrb!=|_@`K?vV_&A58+!u-Gs6x+MGjBnI|qTLFnGH9xvX<aXaWHBd@WW0
 

	
 
literal 0
 
HcmV?d00001
 

	
 
diff --git a/img/baseline-20px.png b/img/baseline-20px.png
 
deleted file mode 100644
 
index 6894c4c8289e8600b595caf70d481324e640b8bd..0000000000000000000000000000000000000000
 
GIT binary patch
 
literal 0
 
HcmV?d00001
 

	
 
literal 127
 
zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)pi0lw^r(L`iUdT1k0gQ7VIDN`6wR
 
zf@f}GdTLN=VoGJ<$y6JlB1KOZ$B>F!Nk9Jow`XSN<z!=HoHesY!R@WWAwG@Mj0y)B
 
YKKcpQXiYX%0xD+kboFyt=akR{0IF0Y6aWAK
 

	
 
diff --git a/index.html b/index.html
 
index 9aa2355b0d5f3dd324c8191637703c944ca14fca..654d5cc338e5cb27b41e09739363b025242d8acf 100644
 
--- a/index.html
 
+++ b/index.html
 
@@ -2,7 +2,7 @@
 
 <html lang="en">
 
   <head>
 
     <meta charset="utf-8">
 
-    <title>Baseline</title>
 
+    <title>Twitter Baseline</title>
 
 
 
     <!-- // Less.js at the ready! -->
 
     <link rel="stylesheet/less" type="text/css" media="all" href="less/baseline.less" />
 
@@ -11,6 +11,7 @@
 
     <!-- // jQuery! -->
 
     <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
 
     <script type="text/javascript" src="http://tablesorter.com/jquery.tablesorter.min.js"></script>
 
+    <script type="text/javascript" src="js/jquery/hashgrid.js"></script>
 
     <script type="text/javascript">
 
       $(document).ready(function(){
 
         // Active state in top nav
 
@@ -36,7 +37,7 @@
 
 <!--
 
 		<style>
 
 		  body {
 
-		    background: url(img/baseline-20px.png) repeat 0 0, url(img/grid-940px.png) repeat-y top center;
 
+		    background: url(img/baseline-10px.png) repeat 0 0, url(img/grid-940px.png) repeat-y top center;
 
 		    background-color: #fff;
 
 		  }
 
 		</style>
 
diff --git a/js/global.js b/js/global.js
 
deleted file mode 100644
 
index a934a3360ef6bdf340a036e6f3475daa7a54103c..0000000000000000000000000000000000000000
 
--- a/js/global.js
 
+++ /dev/null
 
@@ -1,75 +0,0 @@
 
-$(document).ready(function(){
 
-  // Get Heights
 
-  windowHeight = $(window).height();
 
-  documentHeight = $(document).height();
 
-  sidebarHeight = windowHeight - 40;
 
-  containerHeight = windowHeight - 40;
 
-  
 
-  // Get Widths
 
-  windowWidth = $(window).width();
 
-  containerWidth = windowWidth - 200;
 
-  
 
-  if (windowHeight < containerHeight) {
 
-  
 
-    // Set Dimensions for default state (before resize)
 
-    $('div#sidebar').css({
 
-      height: sidebarHeight
 
-    });
 
-    $('div#container').css({
 
-      width: containerWidth,
 
-      height: containerHeight
 
-    });
 
-    
 
-  } else {
 
-  
 
-    // During resize, set widths
 
-    $(window).resize(function() {
 
-      console.log('Window Height: ' + $(window).height() + ', Sidebar Height:' + ($(window).height() - 40));
 
-  
 
-  	  // Get Heights
 
-  	  windowHeight = $(window).height();
 
-  	  sidebarHeight = windowHeight - 40;
 
-  	  containerHeight = windowHeight - 40;
 
-  	  
 
-      // Get Widths
 
-  	  windowWidth = $(window).width();
 
-  	  containerWidth = windowWidth - 200;
 
-  
 
-  	  // Set Dimensions for default state (before resize)
 
-  	  $('div#sidebar').css({
 
-  	    height: sidebarHeight
 
-  	  });
 
-  	  $('div#container').css({
 
-  	    width: containerWidth,
 
-  	    height: containerHeight
 
-  	  });
 
-    });
 
-    // console.log('omgz window is less than container so... fuck.');
 
-    $('div#sidebar').css({
 
-      height: documentHeight - 40
 
-    });
 
-    
 
-  }
 
-  
 
-  
 
-  
 
-/*
 
-  // Toggle Calendars
 
-  $('div#sidebar ul li a').click(function() {
 
-    if ($(this).is('#toggleMonthView')) {
 
-      console.log('toggle month');
 
-      $(this).addClass('active');
 
-      $('#toggleListView').removeClass('active');
 
-      $('table#monthView').show();
 
-      $('table#listView').hide();
 
-    } else {
 
-      console.log('toggle list');
 
-      $(this).addClass('active');
 
-      $('#toggleMonthView').removeClass('active');
 
-      $('table#listView').show();
 
-      $('table#monthView').hide();
 
-    }
 
-    return false;
 
-  });    
 
-*/
 
-});
 
diff --git a/js/jquery/hashgrid.js b/js/jquery/hashgrid.js
 
new file mode 100755
 
index 0000000000000000000000000000000000000000..db7af7989499dd359737a880828f8d1b08571f81
 
--- /dev/null
 
+++ b/js/jquery/hashgrid.js
 
@@ -0,0 +1,340 @@
 
+/**
 
+ * hashgrid (jQuery version)
 
+ * http://github.com/dotjay/hashgrid
 
+ * Version 5, 3 Nov 2010
 
+ * Written by Jon Gibbins, dotjay.co.uk, accessibility.co.uk
 
+ * Contibutors:
 
+ * Sean Coates, seancoates.com
 
+ * Phil Dokas, jetless.org
 
+ *
 
+ * // Using a basic #grid setup
 
+ * var grid = new hashgrid();
 
+ *
 
+ * // Using #grid with a custom id (e.g. #mygrid)
 
+ * var grid = new hashgrid("mygrid");
 
+ *
 
+ * // Using #grid with additional options
 
+ * var grid = new hashgrid({
 
+ *     id: 'mygrid',            // id for the grid container
 
+ *     modifierKey: 'alt',      // optional 'ctrl', 'alt' or 'shift'
 
+ *     showGridKey: 's',        // key to show the grid
 
+ *     holdGridKey: 'enter',    // key to hold the grid in place
 
+ *     foregroundKey: 'f',      // key to toggle foreground/background
 
+ *     jumpGridsKey: 'd',       // key to cycle through the grid classes
 
+ *     numberOfGrids: 2,        // number of grid classes used
 
+ *     classPrefix: 'class',    // prefix for the grid classes
 
+ *     cookiePrefix: 'mygrid'   // prefix for the cookie name
 
+ * });
 
+ */
 
+if (typeof jQuery == "undefined") {
 
+	alert("Hashgrid: jQuery not loaded. Make sure it's linked to your pages.");
 
+}
 
+
 
+
 
+/**
 
+ * hashgrid overlay
 
+ */
 
+var hashgrid = function(set) {
 
+
 
+	var options = {
 
+		id: 'grid',             // id for the grid container
 
+		modifierKey: null,      // optional 'ctrl', 'alt' or 'shift'
 
+		showGridKey: 'g',       // key to show the grid
 
+		holdGridKey: 'h',       // key to hold the grid in place
 
+		foregroundKey: 'f',     // key to toggle foreground/background
 
+		jumpGridsKey: 'j',      // key to cycle through the grid classes
 
+		numberOfGrids: 1,       // number of grid classes used
 
+		classPrefix: 'grid-',   // prefix for the grid classes
 
+		cookiePrefix: 'hashgrid'// prefix for the cookie name
 
+	};
 
+	var overlayOn = false,
 
+		sticky = false,
 
+		overlayZState = 'B',
 
+		overlayZBackground = -1,
 
+		overlayZForeground = 9999,
 
+		classNumber = 1;
 
+
 
+	// Apply options
 
+	if (typeof set == 'object') {
 
+		var k;
 
+		for (k in set) options[k] = set[k];
 
+	}
 
+	else if (typeof set == 'string') {
 
+		options.id = set;
 
+	}
 
+
 
+	// Remove any conflicting overlay
 
+	if ($('#' + options.id).length > 0) {
 
+		$('#' + options.id).remove();
 
+	}
 
+
 
+	// Create overlay, hidden before adding to DOM
 
+	var overlayEl = $('<div></div>');
 
+	overlayEl
 
+		.attr('id', options.id)
 
+		.css({
 
+			display: 'none',
 
+			'pointer-events': 'none'
 
+		});
 
+	$("body").prepend(overlayEl);
 
+	var overlay = $('#' + options.id);
 
+
 
+	// Unless a custom z-index is set, ensure the overlay will be behind everything
 
+	if (overlay.css('z-index') == 'auto') overlay.css('z-index', overlayZBackground);
 
+
 
+	// Override the default overlay height with the actual page height
 
+	var pageHeight = parseFloat($(document).height());
 
+	overlay.height(pageHeight);
 
+
 
+	// Add the first grid line so that we can measure it
 
+	overlay.append('<div id="' + options.id + '-horiz" class="horiz first-line">');
 
+
 
+	// Position off-screen and display to calculate height
 
+	var top = overlay.css("top");
 
+	overlay.css({
 
+		top: "-999px",
 
+		display: "block"
 
+	});
 
+
 
+	// Calculate the number of grid lines needed
 
+	var line = $('#' + options.id + '-horiz'),
 
+		lineHeight = line.outerHeight();
 
+
 
+	// Hide and reset top
 
+	overlay.css({
 
+		display: "none",
 
+		top: top
 
+	});
 
+
 
+	// Break on zero line height
 
+	if (lineHeight <= 0) return true;
 
+
 
+	// Add the remaining grid lines
 
+	var i, numGridLines = Math.floor(pageHeight / lineHeight);
 
+	for (i = numGridLines - 1; i >= 1; i--) {
 
+		overlay.append('<div class="horiz"></div>');
 
+	}
 
+
 
+	// vertical grid
 
+	overlay.append($('<div class="vert-container"></div>'));
 
+	var overlayVert = overlay.children('.vert-container');
 
+	var gridWidth = overlay.width();
 
+	overlayVert.css({width: gridWidth, position: 'absolute', top: 0});
 
+	overlayVert.append('<div class="vert first-line">&nbsp;</div>');
 
+
 
+	// 30 is an arbitrarily large number...
 
+	// can't calculate the margin width properly
 
+	for (i = 0; i < 30; i++) {
 
+		overlayVert.append('<div class="vert">&nbsp;</div>');
 
+	}
 
+
 
+	overlayVert.children()
 
+		.height(pageHeight)
 
+		.css({display: 'inline-block'});
 
+
 
+	// Check for saved state
 
+	var overlayCookie = readCookie(options.cookiePrefix + options.id);
 
+	if (typeof overlayCookie == 'string') {
 
+		var state = overlayCookie.split(',');
 
+		state[2] = Number(state[2]);
 
+		if ((typeof state[2] == 'number') && !isNaN(state[2])) {
 
+			classNumber = state[2].toFixed(0);
 
+			overlay.addClass(options.classPrefix + classNumber);
 
+		}
 
+		if (state[1] == 'F') {
 
+			overlayZState = 'F';
 
+			overlay.css('z-index', overlayZForeground);
 
+		}
 
+		if (state[0] == '1') {
 
+			overlayOn = true;
 
+			sticky = true;
 
+			showOverlay();
 
+		}
 
+	}
 
+	else {
 
+		overlay.addClass(options.classPrefix + classNumber);
 
+	}
 
+
 
+	// Keyboard controls
 
+	$(document).bind('keydown', keydownHandler);
 
+	$(document).bind('keyup', keyupHandler);
 
+
 
+	/**
 
+	 * Helpers
 
+	 */
 
+
 
+	function getModifier(e) {
 
+		if (options.modifierKey == null) return true; // Bypass by default
 
+		var m = true;
 
+		switch(options.modifierKey) {
 
+			case 'ctrl':
 
+				m = (e.ctrlKey ? e.ctrlKey : false);
 
+				break;
 
+
 
+			case 'alt':
 
+				m = (e.altKey ? e.altKey : false);
 
+				break;
 
+
 
+			case 'shift':
 
+				m = (e.shiftKey ? e.shiftKey : false);
 
+				break;
 
+		}
 
+		return m;
 
+	}
 
+
 
+	function getKey(e) {
 
+		var k = false, c = (e.keyCode ? e.keyCode : e.which);
 
+		// Handle keywords
 
+		if (c == 13) k = 'enter';
 
+		// Handle letters
 
+		else k = String.fromCharCode(c).toLowerCase();
 
+		return k;
 
+	}
 
+
 
+	function saveState() {
 
+		createCookie(options.cookiePrefix + options.id, (sticky ? '1' : '0') + ',' + overlayZState + ',' + classNumber, 1);
 
+	}
 
+
 
+	function showOverlay() {
 
+		overlay.show();
 
+		overlayVert.css({width: overlay.width()});
 
+		// hide any vertical blocks that aren't at the top of the viewport
 
+		overlayVert.children('.vert').each(function () {
 
+			$(this).css('display','inline-block');
 
+			if ($(this).offset().top > 0) {
 
+				$(this).hide();
 
+			}
 
+		});
 
+	}
 
+
 
+	/**
 
+	 * Event handlers
 
+	 */
 
+
 
+	function keydownHandler(e) {
 
+		var source = e.target.tagName.toLowerCase();
 
+		if ((source == 'input') || (source == 'textarea') || (source == 'select')) return true;
 
+		var m = getModifier(e);
 
+		if (!m) return true;
 
+		var k = getKey(e);
 
+		if (!k) return true;
 
+		switch(k) {
 
+			case options.showGridKey:
 
+				if (!overlayOn) {
 
+					showOverlay();
 
+					overlayOn = true;
 
+				}
 
+				else if (sticky) {
 
+					overlay.hide();
 
+					overlayOn = false;
 
+					sticky = false;
 
+					saveState();
 
+				}
 
+				break;
 
+			case options.holdGridKey:
 
+				if (overlayOn && !sticky) {
 
+					// Turn sticky overlay on
 
+					sticky = true;
 
+					saveState();
 
+				}
 
+				break;
 
+			case options.foregroundKey:
 
+				if (overlayOn) {
 
+					// Toggle sticky overlay z-index
 
+					if (overlay.css('z-index') == overlayZForeground) {
 
+						overlay.css('z-index', overlayZBackground);
 
+						overlayZState = 'B';
 
+					}
 
+					else {
 
+						overlay.css('z-index', overlayZForeground);
 
+						overlayZState = 'F';
 
+					}
 
+					saveState();
 
+				}
 
+				break;
 
+			case options.jumpGridsKey:
 
+				if (overlayOn && (options.numberOfGrids > 1)) {
 
+					// Cycle through the available grids
 
+					overlay.removeClass(options.classPrefix + classNumber);
 
+					classNumber++;
 
+					if (classNumber > options.numberOfGrids) classNumber = 1;
 
+					overlay.addClass(options.classPrefix + classNumber);
 
+					showOverlay();
 
+					if (/webkit/.test( navigator.userAgent.toLowerCase() )) {
 
+						forceRepaint();
 
+					}
 
+					saveState();
 
+				}
 
+				break;
 
+		}
 
+	}
 
+
 
+	function keyupHandler(e) {
 
+		var m = getModifier(e);
 
+		if (!m) return true;
 
+		var k = getKey(e);
 
+		if (!k) return true;
 
+		if ((k == options.showGridKey) && !sticky) {
 
+			overlay.hide();
 
+			overlayOn = false;
 
+		}
 
+	}
 
+
 
+	/**
 
+	 * Cookie functions
 
+	 *
 
+	 * By Peter-Paul Koch:
 
+	 * http://www.quirksmode.org/js/cookies.html
 
+	 */
 
+	function createCookie(name,value,days) {
 
+		if (days) {
 
+			var date = new Date();
 
+			date.setTime(date.getTime()+(days*24*60*60*1000));
 
+			var expires = "; expires="+date.toGMTString();
 
+		}
 
+		else var expires = "";
 
+		document.cookie = name+"="+value+expires+"; path=/";
 
+	}
 
+
 
+	function readCookie(name) {
 
+		var nameEQ = name + "=";
 
+		var ca = document.cookie.split(';');
 
+		for(var i=0;i < ca.length;i++) {
 
+			var c = ca[i];
 
+			while (c.charAt(0)==' ') c = c.substring(1,c.length);
 
+			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
 
+		}
 
+		return null;
 
+	}
 
+
 
+	function eraseCookie(name) {
 
+		createCookie(name,"",-1);
 
+	}
 
+
 
+	/**
 
+	 * Forces a repaint (because WebKit has issues)
 
+	 * http://www.sitepoint.com/forums/showthread.php?p=4538763
 
+	 * http://www.phpied.com/the-new-game-show-will-it-reflow/
 
+	 */
 
+	function forceRepaint() {
 
+		var ss = document.styleSheets[0];
 
+		try {
 
+			ss.addRule('.xxxxxx', 'position: relative');
 
+			ss.removeRule(ss.rules.length - 1);
 
+		} catch(e){}
 
+	}
 
+
 
+}
 
+
 
+
 
+/**
 
+ * You can call hashgrid from your own code, but it's loaded here as
 
+ * an example for your convenience.
 
+ */
 
+$(document).ready(function() {
 
+
 
+	var grid = new hashgrid({
 
+		numberOfGrids: 2
 
+	});
 
+
 
+});
 
diff --git a/less/docs.less b/less/docs.less
 
index 165ddb142019d6ec45aae1fa3fdbb3cbcea3bfdb..30b561118c290925a213d987691dfcbeafeb8f44 100644
 
--- a/less/docs.less
 
+++ b/less/docs.less
 
@@ -1,3 +1,10 @@
 
+body {
 
+  #gradient > .vertical-three-colors(#eee, #fff, 0.15, #fff);
 
+  background-attachment: fixed;
 
+  background-position: 0 40px;
 
+  position: relative;
 
+}
 
+
 
 // Give us some love
 
 header,
 
 section,
 
@@ -77,3 +84,30 @@ aside {
 
 section {
 
   margin-bottom: 40px;
 
 }
 
+
 
+// Hashgrid grid
 
+/**
 
+ * Grid
 
+ */
 
+#grid {
 
+  width: 980px;
 
+  position: absolute;
 
+  top: 0;
 
+  left: 50%;
 
+  margin-left: -490px;
 
+}
 
+#grid div.vert {
 
+  width: 39px;
 
+  border: solid darkturquoise;
 
+  border-width: 0 1px;
 
+  margin-right: 19px;
 
+}
 
+#grid div.vert.first-line {
 
+  margin-left: 19px;
 
+}
 
+#grid div.horiz {
 
+  height: 19px;
 
+  border-bottom: 1px dotted rgba(255,0,0,.25);
 
+  margin: 0;
 
+  padding: 0;
 
+}
 
diff --git a/less/scaffolding.less b/less/scaffolding.less
 
index 2191d98b3f3f805b62eb3b60f1cb4f0be5bf1aa8..88bcf714a9f075cd7ba60033022f21ff95efc776 100644
 
--- a/less/scaffolding.less
 
+++ b/less/scaffolding.less
 
@@ -7,7 +7,7 @@
 
 -------------------------------------------------- */
 
 
 
 div.row {
 
-  .clearfix;
 
+  .clearfix();
 
   div.span1   { .columns(1); }
 
   div.span2   { .columns(2); }
 
   div.span3   { .columns(3); }
 
@@ -34,8 +34,6 @@ html, body {
 
   background-color: #fff;
 
 }
 
 body {
 
-  #gradient > .vertical-three-colors(#eee, #fff, 0.25, #fff);
 
-  background-attachment: fixed;
 
   margin: 0;
 
   .sans-serif(normal,14px,20px);
 
   color: @gray;
 
diff --git a/readme.markdown b/readme.markdown
 
index 36b357b31afdee5fffbeddeba3144ffbd98d9778..41966346963824f2ce5497b8275c3a15c2044ac9 100644
 
--- a/readme.markdown
 
+++ b/readme.markdown
 
@@ -1,13 +1,4 @@
 
 TODOS
 
 
 
-* Write "Using Twitter BP" section
 
-** Two ways to use: LESS.js or compiled
 
-** Not meant to be 100% bulletproof, but is 90% bulletproof (stats?)
 
-** Advanced framework for fast prototyping, internal app development, bootstraping new websites
 
-** Can be easily modified to provide more legacy support
 
-
 
-* Add grid examples back in
 
 * Cross browser checks? Show this anywhere?
 
-* Add layouts section back in
 
-
 
-* Point JS libraries to public library links instead of within the repo
 
\ No newline at end of file
 
+* Add layouts section back in
 
\ No newline at end of file
rhodecode/tests/fixtures/git_diff_chmod.diff
Show inline comments
 
new file 100644
 
diff --git a/work-horus.xls b/work-horus.xls
 
old mode 100644
 
new mode 100755
rhodecode/tests/fixtures/git_diff_mod_single_binary_file.diff
Show inline comments
 
new file 100644
 
diff --git a/US Warszawa.jpg b/US Warszawa.jpg
 
index 5a4b530a9322aad2b13d39a423a6a93146a09a29..b3b889566812a77f52376379e96d32d3db117150
 
GIT binary patch
 
literal 85172
 
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
 
T!viJ;E(+{1YEXtu4BY<*Qm7~*
 

	
rhodecode/tests/fixtures/git_diff_rename_file.diff
Show inline comments
 
new file 100644
 
diff --git a/work-horus.xls b/file.xls
 
similarity index 100%
 
rename from work-horus.xls
 
rename to file.xls

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)