Skip to content

Org-mode exporter for Leanpub books - mirrored from GitLab

License

Notifications You must be signed in to change notification settings

zzamboni/ox-leanpub

Repository files navigation

ox-leanpub: Leanpub book exporter for Org mode

https://melpa.org/packages/ox-leanpub-badge.svg

Ox-leanpub includes Org Mode export backends to publish books and courses with Leanpub. ox-leanpub allows you to write your material entirely in Org mode, and manages the production of the files and directories needed for Leanpub to render your book. I use this package to publish my books.

This package contains three libraries:

  • ox-leanpub-markua.el exports Org files in Leanpub’s Markua format, the default and recommended format for Leanpub books and courses
  • ox-leanpub-markdown.el exports Org files in Leanpub Flavored Markdown (LFM), the original markup format for Leanpub books.
  • ox-leanpub-book.el exports an Org file in multiple files and directories in the structure required by Leanpub, including the necessary manuscript/ directory and the Book.txt, Sample.txt and Subset.txt files. It can use either Markua or LFM as the export backend.

Note: you should use the Markua exporter, as it’s more mature, complete and actively developed by me. Some Org constructs might not be exported correctly to Markdown.

If you have any feedback or bug reports, please open an issue at https://gitlab.com/zzamboni/ox-leanpub/-/issues.

If you want to see a real-world example of how to use it, you can find at https://github.com/zzamboni/emacs-org-leanpub the source of my book Publishing with Emacs, Org mode and Leanpub.

Table of Contents

Installation

From MELPA

You can install the package directly from MELPA. For example, using use-package:

(use-package ox-leanpub
  :after org)

Note: installing the ox-leanpub package will also install ox-gfm, which is used for exporting tables in Markua format.

By default, the ox-leanpub module sets things up for exporting books in Markua format. If you want to export your books in LFM format, you need to additionally load the ox-leanpub-markdown exporter and tell ox-leanpub-book to set up the corresponding menu entries, as follows:

(use-package ox-leanpub
  :after org
  :config
  (require 'ox-leanpub-markdown)
  (org-leanpub-book-setup-menu-markdown))

In Doom Emacs

If you use Doom Emacs, add the following line to your packages.el file:

(package! ox-leanpub)

And the following to your config.el file:

(use-package! ox-leanpub
  :after org)

If you need to export to Markdown, add the :config section exactly as shown before.

From source

If you want to install from the source in GitLab, you can clone this repository using git. For example:

cd ~/.emacs.d/lisp
git clone https://gitlab.com/zzamboni/ox-leanpub.git

ox-leanpub-markua depends on ox-gfm for exporting tables, so you need to install it as well. Easiest is to install it from MELPA using M-x package-install, or use-package:

(use-package ox-gfm
  :after org)

Finally, you need to tell Emacs to load the module from the path where you installed it. For example:

(use-package ox-leanpub
  :path "~/.emacs.d/lisp/ox-leanpub"
  :after org
  :config
  (require 'ox-leanpub-markdown)
  (org-leanpub-book-setup-menu-markdown))

Usage

Depending on whether you load the Markua or Markdown exporter, you will see the corresponding new sections in Org’s export menu (C-c C-e), called “Export to Leanpub Markua” and “Export to Leanpub Markdown”:

[M] Export to Leanpub Markua
    [M] To temporary buffer       [m] To file
    [o] To file and open
    [b] Book: Whole book          [s] Book: Subset

[L] Export to Leanpub Markdown
    [L] To temporary buffer       [l] To file
    [o] To file and open
    [b] Book: Whole book          [s] Book: Subset

The “buffer” and “file” options export the whole file to the corresponding format, but without any further structuring. You can use these if you want to convert a whole book for using with Leanpub’s in-browser editor, for example.

The “Book” options do whole-book export in the structure required by Leanpub:

  • “Book: Whole book” exports the whole book as one-file-per-chapter;
  • “Book: Subset” exports only the chapters that should be included in Subset.txt (if any), according to the rules listed below, to be able to quickly preview them using LeanPub’s subset-preview feature;
    • The subset export can be temporarily restricted to the current chapter (regardless of the #+LEANPUB_BOOK_WRITE_SUBSET setting, see below) by pressing C-s in the Org Mode Export screen to set “Export scope” to “Subtree”.

The first time you do a Book export, the following directory and symlink structure will be created:

.
├── images -> manuscript/resources/images
└── manuscript
    ├── images -> resources/images
    └── resources
        └── images

In short, this is what the Book export operation does:

  • Creates a manuscript folder if needed, under which all other files are stored.
  • A resources/images directory is created inside manuscript, as required by the Leanpub Markua processor (this is not required by the LFM processor, but the same structure is used).
  • Symlinks to the images directory are created both from the top-level directory, and from the manuscript directory, to allow referencing the same image files both from the Org file and from the exported Markua files.
  • Exports one .markua or .md file for each top-level header (chapter) in your book.
  • Creates the Book.txt file with the filenames corresponding to the chapters of your book.
    • Depending on the exporter settings (see below), the Subset.txt and Sample.txt files may also be created.

The book files are created inside manuscript and populated as follows:

  • Book.txt with all chapters, except those tagged with noexport.
  • Sample.txt with all chapters tagged with sample. Note: this file is only created when exporting LFM. In Markua output, all headings tagged with sample are given the sample: true attribute as documented in the Markua manual.
  • Subset.txt with chapters depending on the value of the #+LEANPUB_WRITE_SUBSET file property (see Configuration below):
    • Default or none: not created.
    • tagged: use all chapters tagged subset.
    • all: use the same chapters as Book.txt.
    • sample: use same chapters as Sample.txt.
    • current: export the current chapter (where the cursor is at the moment of the export) as the contents of Subset.txt. This can be set temporarily (for a single export) by pressing C-s in the Export screen to set “Export scope” to “Subtree”.

The exported chapter files are named as follows:

  1. If the heading has an EXPORT_FILE_NAME property, it is used, unless the #+LEANPUB_BOOK_RECOMPUTE_FILENAMES file property is set.
    • Note: this filename should already specify the output directory and extension, e.g. manuscript/chapter.markua
  2. If the #+LEANPUB_BOOK_ID_AS_FILENAME is set and the heading has a NAME, CUSTOM_ID or ID property, it is used as the base filename, and used to construct the filename inside manuscript. The resulting final filename is stored in the EXPORT_FILE_NAME property.
  3. Otherwise, the filename is generated based on the heading title by lowercasing it and replacing all non-alphanumeric characters with hyphens. The resulting final filename is likewise stored in EXPORT_FILE_NAME.

The last-used filename is stored in the EXPORT_FILE_NAME property of the corresponding heading. By default, once this property is set it is not modified on future exports. If you set the #+LEANPUB_BOOK_RECOMPUTE_FILENAMES attribute in your file, the EXPORT_FILE_NAME property will be updated every time the book is exported. This can be useful to keep the filenames in sync when you change the heading titles in your document, but be aware that the file exported with the old name will not be removed automatically.

Special heading tags

If a heading has the frontmatter, mainmatter or backmatter tags, the corresponding directive (they work in both Markdown and Markup modes) is inserted in the output, before the headline. This way, you only need to tag the first chapter of the front, main, and backmatter, respectively.

If a level-1 heading has the part tag, it is exported as a part heading (“# Title #” in Markua, “-# Title” in LFM).

If a heading has the sample tag in a Markua export, the conditional attribute {sample: true} is inserted before the heading in the output, to indicate that the section should be included in the book sample generated by Leanpub. If a heading has the sample tag in a Markdown export, the corresponding chapter is added to the Sample.txt file.

If a heading has the nobook tag, the conditional attribute {book: false} is inserted before the heading in the output, to indicate that the section should not be included in the book. You can specify both the nobook and sample tags to flag a section which should only be included in the sample. The nobook tag has no effect in Markdown exports.

Note: noexport and nobook are similar but have different semantics. noexport is interpreted by Org when exporting your file, and it completely omits the corresponding headings from the output, whereas nobook includes the text, but flags it accordingly for Leanpub to ignore it when rendering the final book.

Attributes

Both LFM and Leanpub support specifying attributes for different elements using attribute lines. Both ox-leanpub-markua and ox-leanpub-markdown support specifying attributes as follows:

  • An element’s #+NAME, ID or CUSTOM_ID, if specified, are used for the id attribute.
  • An element’s #+CAPTION, if specified, is used for the caption attribute in Markua and the title attribute in LFM (see Block Captions for details of how captions are produced in block elements).
  • Other attributes can be specified in an #+ATTR_LEANPUB line before the corresponding element. The syntax is the same as for Org header arguments. These are merged with the previous one if specified. Attributes specified in #+ATTR_LEANPUB override those specified through other mechanisms.

Example:

#+name: system-diagram
#+caption: Architecture diagram
#+attr_leanpub: :width 30%
[[file:images/diagram.png]]

Gets exported in Markua as:

{width: "30%", id: "system-diagram", caption: "Architecture diagram"}
![Architecture diagram](images/diagram.png)

And in LFM as:

{width="30%", id="system-diagram", title="Architecture diagram"}
![Architecture diagram](images/diagram.png)

Block elements

ox-leanpub supports all Leanpub block elements in Markua export:

Block typeGets exported as
#+begin/end_aside{aside}
#+begin/end_blockquote{blockquote}
#+begin/end_blurb{blurb}
#+begin/end_center{blurb, class: "center"}
#+begin/end_discussion{blurb, class: "discussion"}
#+begin/end_error{blurb, class: "error"}
#+begin/end_exercise{blurb, class: "exercise"}
#+begin/end_information{blurb, class: "information"}
#+begin/end_note{blurb, class: "information"}
#+begin/end_question{blurb, class: "question"}
#+begin/end_quote{blockquote}
#+begin/end_tip{blurb, class: "tip"}
#+begin/end_warning{blurb, class: "warning"}

You can specify a custom icon for a block using the :icon attribute in an #+ATTR_LEANPUB line. For example:

#+ATTR_LEANPUB: :icon github
#+begin_tip
Tip with a GitHub icon instead of the default.
#+end_tip

You can change the default icon for a block for the whole document, or you can even define your own block types, by using #+MARKUA_BLOCK lines. The syntax is:

#+MARKUA_BLOCK: blockname [:class classname] [:icon iconname]

Where blockname and at least one of :class or :icon needs to be specified:

  • blockname is the name of the block to define. Can be one of the existing block names (to redefine it) or a new one.
  • classname (optional) is the name of an existing supported Markua block class (as listed in the table above). It can be omitted to use a plain {blurb} block.
  • iconname (optional) is a valid icon name to use for the block.

You can define multiple block types, each on their own #+MARKUA_BLOCK line. For example, you can change the default icon of tip blocks to be a lightbulb instead of the default key icon:

#+MARKUA_BLOCK: tip :class tip :icon lightbulb

#+begin_tip
Tip with a lightbulb!
#+end_tip

You can also define completely new block types:

#+MARKUA_BLOCK: leanpub :icon leanpub

#+begin_leanpub
Leanpub block!
#+end_leanpub

Block captions

If a #+CAPTION is specified for a block, it is exported as a headline at the top of the block. By default, the level of the headline is one below the current level (e.g. if the block is under a level-2 headline, its caption will be produced as a level-3 headline). You can configure this for the whole document by setting the #+MARKUA_BLOCK_CAPTION_LEVEL option, or for individual blocks by specifying the :caption-level option in the #+ATTR_LEANPUB line. Valid values for this option are:

  • same: the caption will be produced as a same-level headline;
  • A number 1-9: the caption will be produced as a headline of the specified level;
  • below (or anything else): default behavior, caption will be produced at one level below the current one.

Exporting books and courses

Leanpub Markua supports exporting both books and courses. The results are largely the same, currently with one exception:

You can tell ox-leanpub-markua how your buffer should be exported by setting the #+MARKUA_EXPORT_TYPE option. Its default value is "book". If you are exporting a course, set it as follows:

#+MARKUA_EXPORT_TYPE: course

You can also set this parameter for an individual block by specifying the :export-type argument in #+ATTR_LEANPUB, as follows:

#+ATTR_LEANPUB: :export-type course
#+begin_exercise
 ...
#+end_exercise

Code block captions

Normally, a caption for a code block is specified using the standard #+CAPTION attribute, like this:

#+caption: My code block
#+begin_src bash
echo "Hi"
#+end_src

You can configure ox-leanpub-markua to automatically generate the caption using the :tangle or :noweb-ref attributes, if present, using the #+MARKUA_TANGLE_CAPTION and #+MARKUA_NOWEB_REF_CAPTION options. Either or both of them can be specified. The format of the generated captions can be configured, see Configuration below for the details. Note: generating captions based on :tangle or :noweb-ref only works if the org-export-use-babel variable is set to nil. This is due to a limitation in org-export (the code block headers are not visible to the exporter if this variable is t, since they are processed before).

Even when these options are enabled, a manually specified #+CAPTION will always take precedence.

Index entries

Leanpub supports producing indices for books using Markua 0.30, so ox-leanpub-markua exports Org-mode index entries using the {i:...} syntax used by Markua. The value given to #+INDEX will be passed as-is into the {i:...} attributes (including any formatting markup, which needs to be provided in Markua format), with one exception: for see and seealso entries, the format should be see=otherentry or seealso=otherentry, and it will be converted to the correct syntax on export. The value given to #+INDEX must not be enclosed in quotes, but the value passed to see or seealso may be enclosed in quotes. Separators such as ! and | must be escaped with a backslash.

Org-mode sourceExported Markua
#+INDEX: "hello"error
#+INDEX: hello{i: "hello"}
#+INDEX: Zamboni, Diego{i: "Zamboni, Diego"}
#+INDEX: Yahoo\!{i: "Yahoo\!"}
#+INDEX: *hello*{i: "*hello*"}
#+INDEX: **hello**{i: "**hello**"}
#+INDEX: hello!Diego{i: "hello!Diego"}
#+INDEX: hello!*Diego*{i: "hello!*Diego*"}
#+INDEX: hello!**Diego**{i: "hello!**Diego**"}
#+INDEX: Diego¦see=hello{i: "Diego¦see{i:'hello'}"}

Calling from Emacs LISP

There are multiple endpoints which can be useful when calling from Emacs LISP, for example from hooks to automatically export the book under certain conditions. Some of the most useful are:

  • org-leanpub-book-export-markdown and org-leanpub-book-export-markua: both can be called without arguments, and export the whole book in the corresponding format.

Configuration

The modules provide reasonable defaults, but you can configure some parameters by specifying keywords at the top of your Org file. The following are recognized:

KeywordDefault valueDescription
#+LEANPUB_BOOK_ID_AS_FILENAMEnilIf set (regardless of its value), use a heading’s NAME, CUSTOM_ID or ID properties (if it has them) to construct the output filename, instead of always using the title.
#+LEANPUB_BOOK_OUTPUT_DIR“manuscript”Subdirectory where the exported files will be created.
#+LEANPUB_BOOK_RECOMPUTE_FILENAMESnilIf set (regardless of its value), update EXPORT_FILE_NAME for all headings on each export, based on the title. Note that if a chapter title has changed since the last export, it will be exported to a new filename, but the old file will not be deleted, you need to do this manually.
#+LEANPUB_BOOK_WRITE_SUBSET“none”What to write to the Subset.txt file. Possible values: none, tagged, all, sample, current.
#+MARKUA_BLOCKnilRedefine or define a new block type. See Block Elements for the syntax details.
#+MARKUA_EXPORT_TYPE“book”(only for Markua export) Determines the type of export being done. Valid values are “book” and “course”.
#+MARKUA_NOWEB_REF_CAPTIONnil(only for Markua export) If set (regardless of its value), use the value of the :noweb-ref header argument for the caption of source code blocks. For this to work, the org-export-use-babel variable must be set to nil.
#+MARKUA_NOWEB_REF_CAPTION_FMT“«%s»≡”Format to use for captions generated from the :noweb-ref attribute. The string %s is replaced by the :noweb-ref value. The default value can be used (depending on the formatting of your book) to emulate the default output format produced by noweb.
#+MARKUA_TANGLE_CAPTIONnil(only for Markua export) If set (regardless of its value), use the value of the :tangle header argument for the caption of source code blocks. For this to work, the org-export-use-babel variable must be set to nil.
#+MARKUA_TANGLE_CAPTION_FMT”[%s]”Format to use for captions generated from the :tangle attribute. The string %s is replaced by the :tangle value.
#+MARKUA_TANGLE_NOWEB_CAPTION_FMT”[%1$s] «%2$s»≡”Format to use when both :noweb-ref and :tangle are used to generate the caption. The string %1$s is replaced by the value of :tangle, and %2$s by the value of :noweb-ref.

FAQ

Headlines below a certain level are not exported correctly

This is controlled by the Org-mode “H” export option. Its default value is 3, which causes all lower-level headlines to be exported as lists instead. To fix this, you have to increase the value of this option.

This can be done in each file with a line like this:

#+options: h:9

You can also change its default by setting the org-export-headline-levels variable.

Credits

  • The original version of ox-leanpub-markdown.el was written by Juan Reyero as ox-leanpub.el and is still available at https://github.com/juanre/ox-leanpub. I made many changes to fix some bugs and process additional markup elements, and ox-leanpub-markua.el is also derived from it. This repository started as a fork of the original, but given the amount of changes I have recreated it as a standalone repo, to avoid confusion.
  • ox-leanpub-book.el was based originally on code by Lakshmi Narasimhan, but also heavily modified.
  • ox-leanpub-markua.el delegates the work of exporting tables to ox-gfm.

Check out my books!

If you find this package useful, consider supporting me by purchasing my book Publishing with Emacs, Org Mode and Leanpub, or any of my other books at Leanpub!

Disclaimer

I am not associated with Leanpub other than being a happy author. Leanpub is not responsible for this code.

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •