Move diff change description handling into a new DiffField.

DiffField is now responsible for recording change entries for new diffs,
and for showing those entries. This logic is no longer hard-coded into
the template, review_detail view, or ReviewRequestDraft.publish.

Since this (and other similar upcoming fields) require access to state
generated during the review_detail view, I've added an internal
BuiltinLocalsFieldMixin that takes in a locals() and extracts necessary
data from it. This is only meant for internal usage.

The rendered output from DiffField looks the same as it did in the
template. An upcoming change for better change entry rendering will
improve this output a bit.
Handle post-commit for SVN repos that don't use the default layout.

When connecting an SVN repo that doesn't use the default layout (trunk/,
branches/, tags/), the "New Review Request" would just show an empty bottom
panel (and have an un-caught exception to boot).

This change makes it so that if we don't see a 'trunk' directory in the root of
the repository, we'll just return the list of directories in the root as the
"branches" instead of nothing.

While I was doing this, I added some code to sort the branches for standard
layout repos with the Subvertpy backend (which gives us dirents in ctime order
instead of lexical order).

Testing done:
Connected the Apache ASF subversion repo (which has a bunch of projects in the
root) and loaded the new review request page. Saw that I got an alphabetized
list of projects, and could browse the commits on each of those projects as
expected. Verified with both PySVN and Subvertpy backends.

Reviewed at https://reviews.reviewboard.org/r/5486/