From: Carsten Dominik <carsten.dominik@gmail.com>
To: Nicolas Goaziou <n.goaziou@gmail.com>
Cc: Org Mode List <emacs-orgmode@gnu.org>
Subject: Re: [ANN] Org Export in contrib
Date: Sun, 27 Nov 2011 12:06:58 +0100 [thread overview]
Message-ID: <C34D70B3-B649-4774-8548-A5FC62E6012E@gmail.com> (raw)
In-Reply-To: <87ipm8w1jz.fsf@gmail.com>
Hi everyone,
is there anyone who is planning to implement a texinfo
exporter based on org-elements? If not, I would write
this exporter...
- Carsten
On 25.11.2011, at 18:32, Nicolas Goaziou wrote:
> Hello,
>
> I've pushed org-export.el to contrib. It's a general export engine,
> built on top of org-elements aiming at simplifying life of both
> developers and maintainers (and, therefore, of end-users).
>
> It predates org-exp.el and org-special-blocks.el. Though, keep it mind
> that, as advanced as it is, it isn't yet a drop-in replacement for
> them. It still lacks an interface (à la `org-export'), back-ends, and
> tons of testing and improvements. That being said, it's usable anyway
> and one can already write back-ends for it. I'll show a silly example
> later in this mail.
>
> Now, let's have a peek into the guts of that beast.
>
> Besides the parser, the generic exporter is made of three distinct
> parts:
>
> - The communication channel consists in a property list, which is
> created and updated during the process. Its use is to offer every
> piece of information, would it be export options or contextual data,
> all in a single place. The exhaustive list of properties is given in
> "The Communication Channel" section of the file.
>
> - The transcoder walks the parse tree, ignores or treat as plain text
> elements and objects according to export options, and eventually calls
> back-end specific functions to do the real transcoding, concatenating
> their return value along the way.
>
> - The filter system is activated at the very beginning and the very end
> of the export process, and each time an element or an object has been
> converted. It is the entry point to fine-tune standard output from
> back-end transcoders.
>
> The core function is `org-export-as'. It returns the transcoded buffer
> as a string.
>
> In order to derive an exporter out of this generic implementation, one
> can define a transcode function for each element or object. Such
> function should return a string for the corresponding element, without
> any trailing space, or nil. It must accept three arguments:
>
> 1. the element or object itself,
> 2. its contents, or nil when it isn't recursive,
> 3. the property list used as a communication channel.
>
> If no such function is found, that element or object type will simply be
> ignored, along with any separating blank line. The same will happen if
> the function returns the nil value. If that function returns the empty
> string, the type will be ignored, but the blank lines will be kept.
>
> Contents, when not nil, are stripped from any global indentation
> (although the relative one is preserved). They also always end with
> a single newline character.
>
> These functions must follow a strict naming convention:
> `org-BACKEND-TYPE' where, obviously, BACKEND is the name of the export
> back-end and TYPE the type of the element or object handled.
>
> Moreover, two additional functions can be defined. On the one hand,
> `org-BACKEND-template' returns the final transcoded string, and can be
> used to add a preamble and a postamble to document's body. It must
> accept two arguments: the transcoded string and the property list
> containing export options. On the other hand, `org-BACKEND-plain-text',
> when defined, is to be called on every text not recognized as an element
> or an object. It must accept two arguments: the text string and the
> information channel.
>
> Any back-end can define its own variables. Among them, those
> customizables should belong to the `org-export-BACKEND' group. Also,
> a special variable, `org-BACKEND-option-alist', allows to define buffer
> keywords and "#+options:" items specific to that back-end. See
> `org-export-option-alist' for supported defaults and syntax.
>
> Tools for common tasks across back-ends are implemented in the last
> part of the file.
>
>
> * For Maintainers
>
> To word it differently, this exporter doesn't rely on any
> text-property during the process. Thus, it makes
> `org-if-unprotected-at' and alike obsolete in the whole code base. Org
> core doesn't have to bother anymore about its exporter weaknesses.
>
> Also, buffer's pre-processing is reduced to its strict minimum: Babel
> code expansion. No footnote normalization, list markers to add and
> remove...
>
> Being only a beefed-up parse tree reader, any element or object added
> to Elements is available through the exporter with no further
> modification. Back-end just have to create the appropriate new
> transcoders, unless that element or object should be ignored anyway.
>
>
> * For Developers
>
> All data needed is available in two places: the properties associated
> to the element being transcoded, through the use of
> `org-element-get-property', and the communication channel, with the
> help of `plist-get'. Period.
>
> Also, the exporter takes care about all the filtering required by
> options, and enforces the same number of blank lines in the Org buffer
> and in the source code (though this can be overcome with the use of
> filters). It's easier this way to concentrate on the shape of the
> output.
>
> Tools for common tasks (like building table of contents or listings,
> or numbering headlines) are provided in the library.
>
>
> * For Users
>
> Hooks are gone. Sorry. Most of them happened during a pre-process part
> that doesn't exist anymore.
>
> Though, there are three way to configure the output, in increasing
> power:
>
> 1. Variables (customizable or not) are still there, provided by either
> the exporter itself or its back-ends.
>
> 2. Filter sets are provided to fine-tune output of any
> back-end. A filter set is a list of functions, applied in a FIFO
> order, whose signature is the resulting string of the previous
> function (or the back-end output for the first one) and the
> back-end as a symbol. The return value of the last function
> replaces back-end's output. If one of the return values is nil, the
> element or object on which the filters are applied is ignored in
> the final output.
>
> Also, three special filter sets apply on the parse tree, on plain
> text, and on the final output.
>
> For example, the LaTeX back-end has the bad habit to "boldify"
> deadline, scheduled and closed strings close to time-stamps in the
> buffer. I'd rather have them emphasized. Obviously, I don't want to
> annoy other back-ends with this. The following will do the trick.
>
> #+begin_src emacs-lisp
> (add-to-list 'org-export-filter-time-stamp-functions
> (lambda (ts backend)
> (if (not (eq backend 'latex))
> ts
> (replace-regexp-in-string "textbf" "emph" ts))))
> #+end_src
>
> 3. Whole parts of any back-end can be redefined (or advised). For
> example, if I don't like the way the LaTeX back-end transcodes
> verbatim text, I can always create an `org-latex-verbatim' function
> of my own.
>
>
> * A (silly) Back-End: `summary'
>
> I want a back-end, `summary', which only exports headlines of the
> current buffer, in a markdown format. I would like to have the
> opportunity to add a few lines of text before the first headline. It
> should also delimit beginning and end of output by ASCII scissors. Oh,
> and scissors string should be customizable!
>
> As I only want headlines, I only need to implement an
> `org-summary-headline' function. Though, text before the first
> headline in my buffer will be ignored (it isn't an headline).
>
> So this back-end will have to define its own buffer keyword:
> "#+PREAMBLE:". I need to be able to encounter this keyword more than
> once in the buffer as my preamble will probably span on more than one
> line. The following snippet will do this, and provide the text as the
> value of the `:preamble' property in the communication channel. It
> also creates a customizable `org-summary-scissors' variable, which is
> rightfully added to the `org-export-summary' group.
>
> #+begin_src emacs-lisp
> (defcustom org-summary-scissors "--%<--------------------------------\n"
> "String used as a delimiter for summary output.
> It should end with a newline character."
> :group 'org-export-summary
> :type 'string)
> (defvar org-summary-option-alist)
> (add-to-list 'org-summary-option-alist
> '(:preamble "PREAMBLE" nil nil newline))
> #+end_src
>
> Now onto the headline transcoder. A quick look at the
> `org-element-headline-parser' function tell me that `:raw-value'
> property should be enough, as I need no fancy transformation. I might
> want to also use `:level' to get the number of "equal" signs before
> the text, but a longer look at the list of properties offered in the
> communication channel tells me that `org-export-get-relative-level'
> may be more adequate. So be it.
>
> #+begin_src emacs-lisp
> (defun org-summary-headline (headline contents info)
> "Return HEADLINE in a Markdown syntax.
> CONTENTS is the contents of the headline. INFO is the property
> list used as a communication channel."
> (let ((title (org-element-get-property :raw-value headline))
> (pre-blank (org-element-get-property :pre-blank headline))
> (level (org-export-get-relative-level headline info))
> ;; Depth of 6 is a hard limit in HTML (and therefore Markdown)
> ;; syntax.
> (limit (min (plist-get info :headline-levels) 6)))
> (when (<= level limit)
> (concat (make-string level ?=) " " title
> (make-string (1+ pre-blank) ?\n)
> contents))))
> #+end_src
>
> This should be sufficient to take care of document's body. Now, I only
> need to add the scissors, the preamble, and the title in the final
> output. This all happens with the help of the `org-summary-template'
> function.
>
> I remember that "#+TITLE:" belongs to `org-element-parsed-keywords',
> which means that its value isn't a string but a secondary string. As
> I don't want to transcode it (my back-end only knows about headline),
> I'll get the raw value back with `org-element-interpret-secondary'
> function (If I had wanted to transcode it, I would have used
> `org-export-secondary-string' instead).
>
> #+begin_src emacs-lisp
> (defun org-summary-template (contents info)
> "Return complete document transcoded with summary back-end.
> CONTENTS is the body of the document. INFO is the plist used as
> a communication channel."
> (let ((title (org-element-interpret-secondary (plist-get info :title)))
> (preamble (plist-get info :preamble)))
> (concat org-summary-scissors
> (upcase title) "\n\n"
> preamble "\n\n"
> contents
> org-summary-scissors)))
> #+end_src
>
> Now, I can test all of this by with M-: (org-export-as 'summary) on
> a test buffer[1]. So far, so good. But I know better and define an
> interactive function for that important action. While I'm at it, it
> will display my summary in a buffer named "*Summary*".
>
> #+begin_src emacs-lisp
> (defun org-export-as-summary ()
> "Create the summary of the current Org buffer.
> Summary is displayed in a buffer called \"*Summary*\"."
> (interactive)
> (when (eq major-mode 'org-mode)
> (switch-to-buffer (org-export-to-buffer 'summary "*Summary*"))))
> #+end_src
>
> That's all, folks.
>
>
> I'll try to package its first back-end, org-latex.el, into experimental/
> before monday.
>
> Feedback, as always, is welcome.
>
>
> Some text that will probably be ignored.
>
> * Head 1
>
> some text
>
> ** Head 1.1
>
> some text too
>
> *** Head 1.1.1
>
> Some text again
>
> ** Head 1.2
>
> some text
>
> * Head 2 :noexport:
>
> some text
> --8<---------------cut here---------------end--------------->8---
>
>
> Regards,
>
> [1] For example, this one:
> --8<---------------cut here---------------start------------->8---
> #+Title: My Summary Test
> #+Preamble: I hope
> #+Preamble: that it is working
> #+Options: H:2
>
> --
> Nicolas Goaziou
>
next prev parent reply other threads:[~2011-11-27 11:07 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-25 17:32 [ANN] Org Export in contrib Nicolas Goaziou
2011-11-25 18:57 ` Nicolas Goaziou
2011-11-27 11:21 ` Carsten Dominik
2011-11-27 19:54 ` Nicolas Goaziou
2011-11-28 11:40 ` Carsten Dominik
2011-11-28 19:38 ` Nicolas Goaziou
2011-11-27 11:06 ` Carsten Dominik [this message]
2011-11-29 6:15 ` Robert Klein
2011-11-29 6:34 ` Robert Klein
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=C34D70B3-B649-4774-8548-A5FC62E6012E@gmail.com \
--to=carsten.dominik@gmail.com \
--cc=emacs-orgmode@gnu.org \
--cc=n.goaziou@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).