This lets the compiler reason about the lifetimes of objects used by the
postprocessor, if the callback captures variables.
See zoni/obsidian-export#175
Instead of passing clones of context and the markdown tree to
postprocessors, pass them a mutable reference which may be modified
in-place.
This is a breaking change to the postprocessor implementation, changing
both the input arguments as well as the return value:
```diff
- dyn Fn(Context, MarkdownEvents) -> (Context, MarkdownEvents, PostprocessorResult) + Send + Sync;
+ dyn Fn(&mut Context, &mut MarkdownEvents) -> PostprocessorResult + Send + Sync;
```
With this change the postprocessor API becomes a little more ergonomic
to use however, especially making the intent around return statements more clear.
This change introduces a new `--hard-linebreaks` CLI argument. When
used, this converts soft line breaks to hard line breaks, mimicking
Obsidian's "Strict line breaks" setting.
Implementation detail: I considered naming this flag
`--strict-line-breaks` to be consistent with Obsidian itself, however I
feel the name is somewhat misleading and ill-chosen.
This introduces support for postprocessors that are run on the result of
a note that is being embedded into another note. This differs from the
existing postprocessors (which remain unchanged) that run once all
embeds have been processed and merged with the final note.
These "embed postprocessors" may be set through the new
`Exporter::add_embed_postprocessor` method.
This introduces a new `--start-at` CLI argument and corresponding
`start_at()` method on the Exporter type that allows exporting of only a
given subdirectory within a vault.
See the updated README file for more details on when and how this may be
used.
Add support for postprocessing of Markdown prior to writing converted
notes to disk.
Postprocessors may be used when making use of Obsidian export as a Rust
library to do the following:
1. Modify a note's `Context`, for example to change the destination
filename or update its Frontmatter.
2. Change a note's contents by altering `MarkdownEvents`.
3. Prevent later postprocessors from running or cause a note to be
skipped entirely.
Future releases of Obsidian export may come with built-in postprocessors
for users of the command-line tool to use, if general use-cases can be
identified.
For example, a future release might include functionality to make notes
more suitable for the Hugo static site generator. This functionality
would be implemented as a postprocessor that could be enabled through
command-line flags.
This commit fixes a bug where, if a note contained uppercase characters
(for example `Note.md`) but was referred to using lowercase
`(`[[note]]`), that note would not be found.
It's possible to end up with "recursive embeds" when two notes embed
each other. This happens for example when a `Note A.md` contains
`![[Note B]]` but `Note B.md` also contains `![[Note A]]`.
By default, this will trigger an error and display the chain of notes
which caused the recursion.
Using the new `--no-recursive-embeds`, if a note is encountered for a
second time while processing the original note, rather than embedding it
again a link to the note is inserted instead to break the cycle.
See also: https://github.com/zoni/obsidian-export/issues/1
Previously, links referencing a heading (`[[note#heading]]`) would just
link to the file name without including an anchor in the link target.
Now, such references will include an appropriate `#anchor` attribute.
Note that neither the original Markdown specification, nor the more
recent CommonMark standard, specify how anchors should be constructed
for a given heading.
There are also some differences between the various Markdown rendering
implementations.
Obsidian-export uses the [slug] crate to generate anchors which should
be compatible with most implementations, however your mileage may vary.
(For example, GitHub may leave a trailing `-` on anchors when headings
end with a smiley. The slug library, and thus obsidian-export, will
avoid such dangling dashes).
[slug]: https://crates.io/crates/slug
Previously, partial embeds (`![[note#heading]]`) would always include
the entire file into the source note. Now, such embeds will only include
the contents of the referenced heading (and any subheadings).
Links and embeds of [arbitrary blocks] remains unsupported at this time.
[arbitrary blocks]: https://publish.obsidian.md/help/How+to/Link+to+blocks
Links within an embedded note would point to other local resources
relative to the filesystem location of the note being embedded.
When a note inside a different directory would embed such a note, these
links would point to invalid locations.
Now these links are calculated relative to the top note, which ensures
these links will point to the right path.
This refactors the Context to maintain a list of all the files which
have been processed so far in a chain of embeds. This information is
then used to print a more helpful error message to users of the CLI when
RecursionLimitExceeded is returned.