Since writers are normally only used synchronously (i.e. to write one document
at a time), we don't guard modifications to their internal
state (e.g. temporarily replacing the string.Builder in WriteNodesAsString)
against race conditions.
The package global `orgWriter` and corresponding use cases of it (`org.String`,
`$node.String`) break that pattern - the writer is potentially used from
multiple go routines at the same time. This results in race conditions that
manifest as error messages like e.g.
could not write output: runtime error: invalid memory address or nil pointer dereference. Using unrendered content.
Additionally, since we catch panics in `Document.Write`, the corresponding
stack trace is lost and dependents of go-org never know what hit them.
As using a writer across simultaneously across go routines is not a standard
pattern, we'll sync the use of the global `orgWriter` instead of trying to make
the actual writer threadsafe; less code noise for the common use case.
current support for latex fragments was inline only, i.e. lines containing block
elements (e.g. a line starting with `* `, i.e. a headline) will not be parsed
as part of the latex fragment but the respective block element. Parsing latex
blocks at the block level should fix that. Note that in any case we don't do
any processing and just emit the raw latex (leaving the rendering to e.g. js).
The actual parameter parsing logic in emacs org mode is quite complex [1]. All
we want for now is to handle parameter values containing spaces [2]. Splitting
on ` :` gets us close enough for now. As I'm very opposed to copying 100 lines
of parameter parsing logic just to get exports right let's wait for use cases -
no hurt in gathering requirements as we go.
[1] https://github.com/bzg/org-mode/blob/master/lisp/ob-core.el#L1481
[2] I never ran into such parameters before and wrongly assumed that splitting
on spaces would be enough. boy was i wrong - just look at that massive
function [1]! that's why we can't have nice things!
To support code block directives like :exports none we need context - i.e. we
need to have the block and it's results at once and can't just render them
independently.
inside src example blocks lines starting with `\s*,` are escaped - i.e. org
mode will not try to parse them as e.g. a headline. We don't want to render the
escape commata to html so let's take them out - and put them back in before
rendering to org. Doing it this way allows us to render them correctly even
when the input did not include them.
see https://orgmode.org/manual/Literal-Examples.html#Literal-Examples
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.
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.
list items only contain content that is indented to their respective
level. Except when that content is inside a block. To allow for this we have to
ignore the parentStop when parsing a block and just include everything until
the end of that block.
Can't think of any problems with this right now. Let's see if this comes
back to bite me.
While adding another test case from the goorgeous issues it became clear that
inline markup and html entity replacement were erronously applied to raw text
elements like inline code =foo=, src/example/export blocks, example lines,
etc.
To correctly handle those cases in both org and html exports a new
parseRawInline method had to be added.
Also some misc html export whitespace fixes and stuff
I went through the issues of goorgeous and picked a few that seemed easy enough
to add (and added some fore as todos for later). That helped a lot and showed
some bugs / edge cases that required changes.
- the org writer wrote a lot of eol spaces and just removed it whenever
String() was actually called. That worked until now but did not bode with
rendering an empty headline - by removing ALL eol space we would render "* "
back as just "*" -> not a headline anymore.
- the html writer had some special handling for line spacing inside paragraphs
and list items - with the introduction of more blocks we need that handling
everywhere.
As browsers / html renderers are nice enough to collapse whitespace (and
especially collapse "\s*\n" into " ") we can just write out the newlines and
let the renderer take care of the rest.