Inanity 1: Elpher and text/gemini
---------------------------------

The next few posts are kind of a mishmash of project update
announcements mixed with stream-of-consciousness waffle.
Apologies in advance for the incoming inanity!

* * *

As I threatened in the last post, I've spent some time improving
Elpher's handling of the text/gemini document type.  This was
helpfully pushed along by several people who pushed their own patches
along these lines to the repository.  Thank you!  Even though I didn't
wind up merging all of the patches, they were certainly all helpful in
pushing this update forward.

As of version 2.7, elpher properly handles text/gemini in accordance
with the spec.  Prior to this update, the situation was pretty dire.
The text/gemini (t/g from now on) format is wonderfully minimal, but
it is definitely not the case that one can just treat it as plain text
and expect documents to be pleasant to read.

Before you read any further, I want to make clear that I'm absolutely
a fan of the current t/g spec and think it's made the right decisions.
I'm just trying to lay out some of the interesting (transient) side
effects of these decisions.

The reason that one can't treat t/g as plain text is that, unless a
line is in a pre-formatted section of the document, the client is
expected to automatically wrap this line in the instance that it is
"too long" as defined by the client.  Furthermore, each source line
must be treated independently from every other line (with the single
exception of the pre-fromatted mode toggle).  This means that it's
against the rules to reflow a paragraph of source text containing
newlines, and has the consequence hard-wrapped source text winds up
looking horrible - unless you're lucky enough to have a device that
can display a whole line of the length chosen by the author.

By way of illustration, consider the following hard-wrapped t/g source:

-- snip --
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Pharetra
magna ac placerat vestibulum lectus mauris. Suspendisse interdum
consectetur libero id faucibus nisl tincidunt. Semper auctor neque
vitae tempus quam pellentesque. Sagittis eu volutpat odio facilisis
mauris. Sem integer vitae justo eget magna fermentum iaculis.
-- snip --

Now look at what happens when it's displayed using the t/g rendering rules
on a client having only 50 columns to play with:

-- snip --
--------------------------------------------------|
Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do
eiusmod tempor incididunt ut labore et dolore
magna aliqua. Pharetra
magna ac placerat vestibulum lectus mauris.
Suspendisse interdum
consectetur libero id faucibus nisl tincidunt.
Semper auctor neque
vitae tempus quam pellentesque. Sagittis eu
volutpat odio facilisis
mauris. Sem integer vitae justo eget magna
fermentum iaculis.
-- snip --

Pretty ugly!  This is why the t/g spec advises against hard wrapping.
Instead, the ideal approach is to place the whole paragraph on a
single line of the source, which allows clients to wrap it properly.

Of course, this then means that, without special handling, source
t/g documents which are paying attention to the spec are increasingly
tend to look like this:

-- snip --
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pharetra magna ac placerat vestibulum lectus mauris. Suspendisse interdum consectetur libero id faucibus nisl tincidunt. Semper auctor neque vitae tempus quam pellentesque. Sagittis eu volutpat odio facilisis mauris. Sem integer vitae justo eget magna fermentum iaculis.
-- snip --

How does this relate to elpher?

Well, until v2.7, elpher used the same set of functions for rendering
both gopher directory files and t/g documents.  Of course the parsing
code differed, but the rendering code was the same.  This seemed nice
and elegant when I originally wrote it; I even gushed about it [1] on
my phlog.  But this meant that text lines in t/g were rendered in the
same way as info lines in gopher directories, and these - at least the
way the street uses these things - don't come with any expectation of
wrapping.

Of course, emacs wraps all lines by default, but unless specifically
told to it does this without any reference to word boundaries.
Furthermore it does this at the edge of the window.  And I am a very
firm believer in the principle that text lines should be no more than
~70 characters wide.

Thus modern t/g documents started to look like shit in elpher.

So, I bit the bullet and implemented an entirely new rendering
function for t/g.  This was easy, and cleaned up a few other things
along the way.  (This always seems to be the way when implementing
gemini-related stuff!)  This function uses emacs auto-fill mode to
wrap text lines appropriately.  This is the mechanism that magically
wraps long lines when an emacs user presses enter when editing a text
document.  It also automatically indents the next line when the
previous line starts with what looks to be a bullet (e.g. a *).  This
had the nice side effect that bulleted t/g lists were formatted nicely
essentially for free.  (In the end I had to replace this "for free"
mechanism with one more tailored, because the "for free" algorithm
actually looks several lines back and assumes that, if the last two
lines begin with "*", you're actually editing a block comment and will
thus automatically prefix the wrapped portion of the line with a new
"*" - which obviously nobody wants!)

One final gripe: I've had to set the default maximum wrapping width to
80. (The actual width depends on the window size.)  While I would
definitely have preferred to set it to 70, unfortunately (but
understandably) there are still some t/g documents around that are
hard-wrapped. Using 80 means that those continue to display okay
provided the window is sufficiently wide.  Hopefully the prevalence of
hard-wrapped t/g documents will diminish over time, allowing us to set
wrapping widths without having to deal with this trade-off.

Besides the wrapping stuff, treating t/g documents as distinct from
gopher directories meant I could easily get rid of the 6 column left
margin that elpher uses to report selector types in gopher dirs.
Also, we now have distinct (configurable) faces for the different
header types.

Phew.  If you managed to stick with me through all of that, I'm both
baffled and humbled!  Thank you, dear reader.  If you're into Emacs
and Gemini, please give the new Elpher a whirl [2] and let me know
what you think!

---
[1]: gopher://thelambdalab.xyz:70/0/phlog/2019-09-11-Elpher-now-supports-Gemini.txt
[2]: gopher://thelambdalab.xyz:70/1/projects/elpher/