# Vision

Jonathan Aquino [suggests][1] that version control commit messages can
be a form of Literate Programming.

[1]: http://jona.ca/blog/git-commit-messages-are-the-new-literate-programming

The original Literate Programming concept by Donald Knuth suggested that
the code should be embedded in comments describing everything that was
in the head of the author while the code was being written. This never
caught on, perhaps because this leads to code with too long comments.

On the other hand, Jonathan notes that some people write really detailed
Git commit messages.

Would it be feasible to present a Git repository as a collection of
chapters and sections, with each coherent change accompanied with a
descriptive commit message telling the story behind the change?

Using the GitHub API, we can extract commit messages from a repository
and render them as Markdown documents, along with diffs.

I imagine that composing such a repository requires a vastly different
discipline and/or workflow than many of us are used to.

* For example, you don’t just `git commit -am 'Fix bug'`; you actually
start writing your commit message _before_ you start fixing the bug,
while investigating the bug cause, the workarounds, and the solution.
When implementing a new feature, you might start with an empty commit,
explaining the need for the feature and/or its design (like I’m doing
here).
* I also think this requires a good deal of history rewriting. For
example, just now I had to fix the syntax of the hyperlink above, so
that it would be parsed by the Markdown library I chose. This caused a
rebase of the whole repository.
HTML skeleton

Let’s add a simple HTML skeleton in which we will show the repository.
We will show the repo name in the page title, the description as the top
heading, and a list of commits. All these will be populated dynamically,
so we give them IDs.
Display repository description

Let’s try interacting with the GitHub API. As usual, we create an
`XMLHttpRequest`, hook up an event handler, and send the request.

For now, I hardcoded the repository owner and name. In future, they can
be taken from the URL query string.

Also, for simplicity, I treat the description as plain text; I will get
to Markdown formatting later.
Factor out AJAX mechanics

Before we display the list of commits, notice that a single API request
requires quite a few lines of code. Let’s factor out all the repeating
steps in a function.

The two things that change from one API call to another are the URL and
the handler function. However, the handler will always need to parse a
JSON response.
Show list of commits

Let’s now fetch the list of commits and show their summaries, with links
to the same page but with a ?sha=xxxxxx query parameter.

The regular expression there splits a commit message into the summary
and the body, using the topmost sequence of two consecutive newlines as
the separator; if there is none, considers the whole message to be the
summary. The `[^\0]` pattern matches any character including newline but
not including the null character (though hopefully nobody in their right
mind uses null characters in commit messages).
Factor out generation of commit list

The links are there but they don’t work. Since they all lead to the same
page, we’ll have to parse that ?sha= and, depending on its presence,
either show the commit list or details of a specific commit.

Before we do that, though, it makes sense to move the commit listing
functionality into a separate function.
Factor out commit message splitting function

We’ll need this function in at least one more place, so let’s DRY it
out.
Show commit details

Now let’s add an ability to show a specific commit.

In HTML, we add a single `div` for this mode, and inside it a heading
for the commit message summary, a `pre` for the body, and a `section`
for all the diffs.

We style the `commits` list and the `single-commit` div to be visible
only depending on the class of the root `body` element, which we toggle
in specific command handlers.

The `showCommit` function takes a `sha` argument, fetches the commit
details and populates the `single-commit` section.

For now, we are treating everything as plain text.
Render markdown

GitHub has a Markdown API but it suffers from a fundamental flaw: It
takes a single Markdown string, returns an HTML string, and is
Rate-limited. This has two consequences:

* We would make a lot of requests, which would be fulfilled
asynchronously and cause much redisplay.
* The default rate limit for unauthenticated requests is 60 requests per
hour. By browsing the list of commits of a mature repository, we can
exhaust that instantly.

So let’s do markdown rendering on the client, using the [markdown-js][]
library. It is distributed under the MIT license.

[markdown-js]: https://github.com/evilstreak/markdown-js
Fix commit list link formatting

Originally, I just wrapped an `<a href="…">` element around the commit
summary. This was all good when the commit summary was just plain
text. Won’t do when it’s rendered markdown, because <a> is an inline
element while markdown typically produces a block element at the top
level.

While it’s possible to style `<a>` as a block element, it makes
for bad user experience: the link takes all horizontal space, so
careless clicks take the user to the linked page.

So we need a function that will take a DOM node and somehow turn “it”
into a link. How would it work?

* The function is initially invoked on the `<li>` element that wraps
  the whole markdown content.
* We want to wrap as long spans of child nodes as possible.
* We never wrap a block element.
* Neither do we wrap another hyperlink.

So:

* Start with the first child of the context node.
* If it is a _restricted_ element (either a hyperlink or a block
  element), or if it contains a restricted element directly or
  indirectly, then stop before it. Wrap the collected span of child
  nodes in a link.
* For a block element or an inline element containing a link, apply
  recursively.
* An inline element containing a block element is technically a
  violation of HTML, but apply recursively anyway.
* For a link, just skip it.
* Continue until there are no more children.
Format diffs nicely

We’d like to color our diffs. Fortunately, the unified diff format is
easy to parse.

* Split the diff text into lines.
* A line that starts with `@@` is a hunk header. Wrap with `<heading>`.
* Lines that start with a space are context lines. Find the maximum
  sequence and emit it as a single text node.
* Lines that start with `-` or `+` are deleted and added lines. Find
  the maximum sequence and wrap it in an `<del>` or `<ins>`,
  respectively.

Notice also that a hunk header is always followed by a different kind
of line. To simplify code, we can apply the maximum sequence algorithm
to them, too.
Show commit author and date

The commit data contains these, just put them after the commit summary.
Reverse the commit order

GitHub API returns commits in blog order (most recent first). In a
Literate setting, I feel it is more natural to present them in book
order (most recent last).