emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Jason Ross <jasonross1024@gmail.com>
To: Ihor Radchenko <yantar92@gmail.com>
Cc: emacs-orgmode@gnu.org
Subject: Re: Best way to include METAPOST in ConTeXt exporter
Date: Mon, 4 Oct 2021 08:41:03 -0700	[thread overview]
Message-ID: <CABcgBK+RdcGreiPSgcBQ6xEnDmsMACSp3HWj+Zj--07sg4asxg@mail.gmail.com> (raw)
In-Reply-To: <87wnmtb2sb.fsf@localhost>

I had considered using special blocks; they match my mental model the best.
However, they don't provide any support for syntax highlighting or opening
the block in a new major mode buffer. I'm not sure if it's worth giving up
language features in order to use the block that's most intuitive to users.

I'm also considering writing an Org Babel module for METAPOST. This could
allow METAPOST figures to be included with any export backend. However,
if I go this route, there are still some challenges:
1. Getting captions and tags attached to the resulting figures is clumsy.
   As far as I know,  this could be done with the :post header argument
   and a wrapper source block, but this would require boilerplate code
   in documents that use this feature
2. I don't know if there's a reasonable way to leverage ConTeXt's native support
   for METAPOST this way; if I ask Org Babel to generate an SVG, ConTeXt then
   has to parse the SVG and (internally) convert it back into METAPOST to
   render in the document. ConTeXt's SVG support (particularly with mathematical
   symbols) is missing some features, so this will be a lossy process.
   Essentially I'd want the module to return a file most of the time, but
   return raw METAPOST (wrapped in some tags) if the ConTeXt backend is used.

Here's a minimal implementation of the source block concept:

    # Define a macro to add header arguments UNLESS ConTeXt backend is used
    #+MACRO: conditional-header (eval (when (not (eq
org-export-current-backend 'context)) (concat  "#+HEADER: :results
file :file " $1)))

    # Define a wrapper block to annotate source block outputs with
    # caption and name
    #+NAME: wrap_metapost
    #+BEGIN_SRC emacs-lisp :var data="" :var caption="" :var name=""
    (concat
     (when (org-string-nw-p name) (format "#+NAME: %s\n" name))
     (when (org-string-nw-p caption) (format "#+CAPTION: %s\n" caption))
     (if (eq org-export-current-backend 'context)
         (format "#+BEGIN_METAPOST \n%s\n#+END_METAPOST" data)
       data))
    #+END_SRC

    # Minimal Org Babel implementation for METAPOST
    #+BEGIN_SRC emacs-lisp
    (defvar org-babel-default-header-args:metapost
      '((:exports . "results"))
      "Default arguments to use when evaluating a dot source block.")
    (defun org-babel-execute:metapost (body params)
      "Execute a block of METAPOST code with org-babel.
    This function is called by `org-babel-execute-src-block'."
      (if (cdr (assq :file params))
          (let* ((out-file (cdr (assq :file params)))
                 (cmdline (or (cdr (assq :cmdline params))
                              (format "-T%s" (file-name-extension out-file))))
                 (cmd (or (cdr (assq :cmd params)) "mpost"))
                 (coding-system-for-read 'utf-8) ;use utf-8 with sub-processes
                 (coding-system-for-write 'utf-8)
                 (in-file (org-babel-temp-file "metapost-")))
            (with-temp-file in-file
              (insert (org-babel-expand-body:generic body params)))
            (org-babel-eval
             (concat cmd
                     " -s 'outputformat=\"svg\"'"
                     (format " -s 'outputtemplate=\"%s\"'"
(org-babel-process-file-name out-file))
                     " " (org-babel-process-file-name in-file)) "")
            nil)
        body))
    #+END_SRC

    # Example Usage
    {{{conditional-header(foo.svg)}}}
    #+BEGIN_SRC metapost :results drawer :post
wrap_metapost(name="my-name", caption="my-caption", data=*this*)
    beginfig(1);
    draw origin--(100,100)--(200,0)--cycle;
    endfig;
    end;
    #+END_SRC

This kind of works: It exports to HTML with a nice SVG figure and sends raw
METAPOST code to the backend, with #+CAPTION and #+NAME information
attached. Also, links to the figures work in the buffer as well as the pdf.

However, there's a lot I don't like about this.
1. No SVG preview in the buffer since the `conditional-header` macro doesn't
   get expanded until export time
2. Boilerplate; both the `conditional-header` and `wrap_metapost` definitions
   need to be included in the org file
3. Inconvenient to use since I have to add a macro call and a :post argument
   with weird syntax to every METAPOST figure, and the way captions and tags
   are specified is different.



On Mon, Oct 4, 2021 at 1:39 AM Ihor Radchenko <yantar92@gmail.com> wrote:
>
> Jason Ross <jasonross1024@gmail.com> writes:
>
> > Hello,
> >
> > I'd like to include METAPOST figures in the ConTeXt exporter backend I'm
> > developing. However, I don't know of an idiomatic way to add captions and
> > references for the figures.
>
> You can use affiliated keywords:
>
> (defconst org-element-affiliated-keywords
>   '("CAPTION" "DATA" "HEADER" "HEADERS" "LABEL" "NAME" "PLOT" "RESNAME" "RESULT"
>     "RESULTS" "SOURCE" "SRCNAME" "TBLNAME")
>   "List of affiliated keywords as strings.
> By default, all keywords setting attributes (e.g., \"ATTR_LATEX\")
> are affiliated keywords and need not to be in this list.")
>
> > Currently, I export METAPOST with `#+BEGIN_EXPORT metapost` / `#+END_EXPORT`
> > tags. However, this feature seems to be intended for completely "raw"
> > outputs
> > with no markup or tagging in the resulting export. I'm interested in
> > supporting
> > at least `#+NAME` and `#+CAPTION` keywords for METAPOST figures so that they
> > can be referred to in the Org file and also in the exported pdf.
>
>
>
> > What are some better ways of doing something like this? Source blocks? How
> > would
> > a user expect to use a feature like this?
>
>
> You can use a special block:
> #+caption: Sample caption
> #+attr_context: :field value
> #+begin_metapost
> ...
> #+end_metapost
>
> The parsed representation of this element in exporter will be something like:
>
> (special-block (:type "metapost" :begin 292 :end 382 :contents-begin 364 :contents-end 368 :post-blank 0 :post-affiliated 347 :caption (((#("Sample caption" 0 14 (:parent #4))))) :attr_context (":field value")))
>
>
> Best,
> Ihor


  reply	other threads:[~2021-10-04 15:42 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-03 17:53 Best way to include METAPOST in ConTeXt exporter Jason Ross
2021-10-04  8:41 ` Ihor Radchenko
2021-10-04 15:41   ` Jason Ross [this message]
2021-10-04 16:46     ` Ihor Radchenko
2021-10-05 14:40       ` Jason Ross
2021-10-05 19:50         ` Jason Ross
2021-10-13  6:51           ` Ihor Radchenko
2021-10-13  6:54         ` Ihor Radchenko

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=CABcgBK+RdcGreiPSgcBQ6xEnDmsMACSp3HWj+Zj--07sg4asxg@mail.gmail.com \
    --to=jasonross1024@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=yantar92@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).