While example blocks do not render inline markup and are thus parsed raw in
some way, their contents are not literal html and thus still need to be html
escaped.
delimiters are not always 2 in length - $ being the exception. Also we have to
make sure to handle both $ and $$ delimiters.
Not proud of this solution but can't think of anything simpler right now - will
come back to this later hopefully.
The org mode toc OPTION does not just support true/false - it also allows
specifying the max headline level [1] to be included in the toc.
[1] headline level as seen in org mode - not the html tag level
We want original whitespace to be rendered in some cases (e.g. verse
blocks). This requires information about the original whitespace to be
preserved during paragraph parsing. As html ignores (collapses) whitespace by
default we don't have to adapt the html writer and can just selectively enable
rendering of the preseverved whitespace wherever we want it using
css (white-space: pre).
To differentiate meaningful whitespace from document structure based
indentation (i.e. list item base indentation) we need to introduce
document.baseLvl. A paragraph by itself does not have enough information to
differentiate both kinds of whitespace and needs this information as context
[0].
As we're already touching list indentation i went along and improved (fixed?)
descriptive list item indentation rendering in the org writer (it should match
emacs tab behavior - i.e. indent subsequent lines up to the `:: `).
[0] e.g. list items can contain blank lines - a paragraph starting with a blank
line would not know that it is part of a list item / has a base indentation -
the blank line would suggest a baseLvl of 0.
WriteNodesAsString is simple enough to implement but exposing it is helpful in
the implementation of extending writers and we don't aim to keep writer a small
interface so let's expose it.
Extension of the org & html writers is made possible by creating circular
references between the extending and extended writer - that way the extending
writer can forward all methods it doesn't implement to the extended writer and the
extended writer can use the extending writer as the root for method calls to
make sure methods overridden in the extending writer are used even for nested
method calls.
This circular reference leads to problems when cloning writers - cloning the
extended writer merely copies the pointer to the extending writer - i.e. the
extending writer does not get cloned with an updated reference to the extended
writer. Thus method calls to the extending writer act as if no cloning took
place and things break.
The easiest solution is to just get rid of cloning. We could also clone the
ExtendingWriter and replace it's reference to the extended writer with the just
cloned one but that's harder so we just remove it.
As there are a lot of "extending writer" and "extended writer" in the above
paragraphs and I'm too lazy to write up something better here's another attempt
at a TLDR:
Cloning is broken as ExtendingWriter is a reference to a writer that has
a reference to the writer we are cloning - that writer would have to have it's
reference updated but that's hard. So we solve it it by not cloning at all.
fuzzed index out of range and moved range check into for condition as \\
followed by spaces at the end of the inline text should not be turned into an
ExplicitLineBreak (just like \\ not followed by spaces).
Go does not support inheritance, just composition. While composition with type
embedding (i.e. forwarding method calls to the embedded type) can replace
inheritance for most use cases this is not one of them. We really want to
overwrite methods so that method calls from inside the base writer also use the
custom methods ouf our extending writer - naive embedding does not work here
as the this in this.WriteText refers to the embedded type rather than the outer
extending type (see open recursion).
A simple solution is to make a reference of the extending type
available from the extended type and use that for nested method calls. We'll go
with that one as it does not require huge code changes. Another solution would
be to flatten the writing process and not use nested method calls - this is
what blackfriday does. Assuming the current solution works I feel it's cleaner
and keeps the ugliness of simulating inheritance with composition contained to
a small portion of the code while blackfridays approach requires all write
methods to be written in a flat style (i.e. not do nested calls to write by
being called twice with entering / leaving). The current solution becomes ugly
if we want to do multiple levels of extending but i don't expect that to be a
valid use case - if it turns out to be one we can always adapt to it
later. YAGNI.
now that i'm already looking at it due to the bug leenzhu found why not put the
</dt> on a separate line to match the convention - looks better to me; doesn't
change anything.
writer.footnotes must be a pointer as we copy the writer in nodesAsString() and
can thus end up modifying the footnotes.list slice without it being reflected in
the original writer (i.e. when the backing array of the slice changes).
I didn't consider that all newlines in the pre block will be printed and we
thus shouldn't wrap html that has it's tags on separate lines (i.e. contains
superfluous newlines) - wrapping in a div less accurately represents
org-html-export but it provides the same information and gives us more freedom
in the return value of HighlightCodeBlock as well as allowing us to keep the
html tags on new lines (consistency).
I went with 0 based numbering because it was easier but after looking at the
results 0 based numbering looks bad to me... let's start with 1 like everyone
else as it's just a few more lines of code.
I never wanted to reproduce the emacs org-export-as-html output exactly but
rather just provide a sensible exporter - the README should tell users what to
expect here.
- Remove unused footnote section title option
- Move away from maintaining a list of footnotes in the document (only needed
for html export, potential maintainance overhead when modifying the document)
and rather only build it on export when required.
- HTML export: Rename all footnotes to numbers (so we can support anonymous
footnote references by assigning them a number) and export footnotes in order
of reference, not definition. The implementation of this makes it natural to
also stop exporting unused footnote definitions so we do that as well.
- go 1.12 optimizes memory allocation for wasm - see
https://github.com/golang/go/issues/27462. This was causing the demo to OOM
on memory restricted devices (e.g. phones).
- js namespace changed so we need to adapt to that
It's possible for the input to end right after the explicit line break,
i.e. after the second \. This currently leads to an out of range index into
input (as the for loop starts with start+2 and [start:start+1] is the \\).
HTMLWriter uses the document to look up export options and adapt it's
behaviour. The writer.document & log are set in the Before() method during
normal use via document.Write().
Sometimes the writer is used separately and won't have it's Before method
called - in those cases we should use the defaults rather than crashing.
Headlines are nested if their level is higher (more stars) than the current
headline. We're abusing the token.lvl field for this - as headlines can never
be indented we know the indentation must be 0 so we can cache the lvl (count of
stars) of the headline in that field.
This doesn't change anything right now so I'll postpone adding tests and stuff
until there are actual use cases for the AST and stuff.
Being able to very easily get the original [1] Org mode content seems like
something that will come up quite often and is very little code.
[1] it's not really the original content, but rather the pretty printed version
of that - as the semantics don't change it shouldn't matter.
TIL embedded types can be acessed by their non-namespaced name - so there
actually is no need for a type alias to access .strings.Builder, one can just
use .Builder.
The existing approach made it hard to extend existing writers.
With this change, replacing individual methods of a writer is possible by
embedding it.
Sharing the WriteNodes function also removes some unnecesseray duplication, so
win win.
Unlike the other BufferSettings, #+OPTIONS: specifies multiple options and we
cannot just look it up in either BufferSettings or DefaultSettings - both have
to be checked
Leftover from the days before BufferSettings & DefaultSettings - now that those
exists the status keywords are actually defined in
- DefaultSettings["TODO"] for the default
- BufferSettings["TODO"] for any customizations
Also ! i < len => i >= len because it's easier on the eyes