From mboxrd@z Thu Jan 1 00:00:00 1970 From: Thibault Marin Subject: Re: Export tangle filename with source block Date: Sat, 08 Oct 2016 14:36:35 -0500 Message-ID: <87r37qzl8c.fsf@dell-desktop.WORKGROUP> References: <87bn1ewjvd.fsf@dell-desktop.WORKGROUP> Reply-To: thibault.marin@gmx.com Mime-Version: 1.0 Content-Type: text/plain Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:42987) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bsxQL-0001mE-C4 for emacs-orgmode@gnu.org; Sat, 08 Oct 2016 15:36:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bsxQH-0002y7-9J for emacs-orgmode@gnu.org; Sat, 08 Oct 2016 15:36:45 -0400 Received: from mout.gmx.net ([212.227.15.18]:49686) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bsxQG-0002wQ-Um for emacs-orgmode@gnu.org; Sat, 08 Oct 2016 15:36:41 -0400 Received: from dell-desktop ([99.47.196.62]) by mail.gmx.com (mrgmx002) with ESMTPSA (Nemesis) id 0Lh7sF-1b87xR2mOt-00oVMI for ; Sat, 08 Oct 2016 21:36:38 +0200 In-reply-to: <87bn1ewjvd.fsf@dell-desktop.WORKGROUP> List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: Org Mode Hi all, I am following up on a question I posted here a while ago to show my progress in case it can help others and to ask for a few clarifications. I would appreciate any feedback. My goal is to add a label to source blocks on HTML export to indicate the name of the file to which the block is tangled. The issues originally raised were: 1) How to display the label in HTML export? 2) How to get the tangle file name, which may come from 1) a file property (e.g. #+PROPERTY: header-args :tangle file-main.py in the file header), 2) a section property (e.g. :header-args: :tangle file-prop.py in a property drawer), 3) the source block header line (e.g. #+BEGIN_SRC python :tangle no)? It appears that the best way to achieve this is to define a derived backend with special handling for src-block objects as in http://orgmode.org/manual/Advanced-configuration.html. * Example file Here is the example file I am working with. #+BEGIN_SRC org ,#+TITLE: Test ,#+PROPERTY: header-args :tangle file-main.py ,#+NAME: src-no-1 ,#+BEGIN_SRC python :tangle no # SHOULD NOT BE TANGLED (1) ,#+END_SRC ,#+NAME: src-header ,#+BEGIN_SRC python :tangle file-header.py # Tangle to file-header.py ,#+END_SRC ,#+NAME: src-main ,#+BEGIN_SRC python # Tangle to file-main.py ,#+END_SRC ,* section :PROPERTIES: :header-args: :tangle file-prop.py :END: ,#+NAME: src-prop ,#+BEGIN_SRC python :tangle file-prop.py # Tangle to file-prop.py ,#+END_SRC ,#+NAME: src-no-2 ,#+BEGIN_SRC python :tangle no # SHOULD NOT BE TANGLED (2) ,#+END_SRC #+END_SRC * Formatting the label I think I have a satisfactory (at least for me) solution for this: in my src-block exporter I first pass the src-block by the regular HTML exporter: #+BEGIN_SRC emacs-lisp (let ((export-out (org-export-with-backend 'html src-block contents info))) ...) #+END_SRC Later, I add a HTML "
" block under the "
" block for the source.  I do
this using a regexp:
#+BEGIN_SRC emacs-lisp
(let ((src-start-pat "\\(
]+>\\)"))
  (setq export-out
        (replace-regexp-in-string
         src-start-pat
         (concat "\\1
" tang "
") export-out))) #+END_SRC This adds the label on the bottom right corner of the "
" block and uses the
"src-label" class, which can be customized via CSS.


* Getting the tangle filename

I am working with the assumption that this will be done from my src-block
handling function in the derived backend:
#+BEGIN_SRC emacs-lisp
(defun my-html-src-block (src-block contents info)
  ...)

(org-export-define-derived-backend 'my-html 'html
  :translate-alist '((src-block . my-html-src-block)))
#+END_SRC

I run the following code to perform the export using my new backend:
#+BEGIN_SRC emacs-lisp
(org-export-to-file 'my-html (buffer-file-name))
#+END_SRC

*Question 1*: Is the `org-element-src-block-parser' function supposed to resolve
 the tangle filename (including inheritance, i.e. to handle the 3 :tangle
 sources listed above)?

>From the docstring, it would appear that it shouldn't return a :tangle keyword
and that the tangling functions are responsible for choosing the output tangle
file for each block.  Is this correct?

Hoping that my understanding of *Question 1* is correct, I tried to use the
`org-babel-tangle-single-block' and `org-babel-tangle-collect-blocks' functions,
which are used during the actual tangling, to get the tangle filename.

** Working version

Here is what I was able to get to work on my simple example:

#+BEGIN_SRC emacs-lisp

(defun my-html-src-block (src-block contents info)
  "Transcode a SRC-BLOCK element from Org to HTML.
     CONTENTS is nil.  INFO is a plist used as a communication
     channel."
  (let* ((src-block-name (org-element-property :name src-block))
         (src-blocks
          (cdr (car (org-babel-tangle-collect-blocks))))
         tang
         (export-out (org-export-with-backend 'html src-block contents info)))
    (dolist (src-coll src-blocks)
      (when (string= (nth 3 src-coll) src-block-name)
        (setq tang (cdr (assoc :tangle (nth 4 src-coll))))))
    (if (and tang (> (length tang) 0) (not (string= tang "no")))
        (let ((src-start-pat "\\(
]+>\\)"))
          (setq export-out
                (replace-regexp-in-string
                 src-start-pat
                 (concat "\\1
" tang "
") export-out)))) export-out)) #+END_SRC To summarize: - Collect all the tangled blocks - Among these, find the one currently passed as input (match by source block name) - Get the :tangle property from the matching collected source-block The main problem I see which this approach is that it collects all the source blocks for each src-block entry to process. This makes the exporting process slow. Another issue is that this requires named blocks, but this constraint is acceptable for me. ** Improvements (which I cannot get to work) - Add collected blocks to `info' in order to perform the collection only once and re-use it for subsequent blocks: I couldn't get it to work, function arguments seem to be passed by value (?) - Use `org-babel-tangle-single-block' to process only one block at a time, this sounds like the right method. I believe I must first move point to the src-block being processed, which I try to do with (org-babel-goto-named-src-block src-block-name): this gives me the correct tangle filename when run from a simple code snippet in the scratch buffer (using (org-element-map (org-element-parse-buffer) ...)), but results in the wrong tangle file when I do that within the `my-html-src-block' function (the :tangle options passed on the #+BEGIN_SRC line as in case 3. are ignored and are always preempted by the inherited tangle value coming either from the ,#+PROPERTY entry or the PROPERTY drawer value). *Question 2*: How can I use `org-babel-tangle-single-block' within the custom src-block handling function? I notice the (point) value is different after the (org-babel-goto-named-src-block src-block-name) call when used from the `my-html-src-block' function (possibly due to some pre-processing performed on the buffer, I am not sure). Sorry for the lengthy post, I hope it is not out of place on this list. Thanks in advance for any help. thibault * Original message > Hi list, > > I have an org file that I am tangling into multiple files, and exporting > to html. What I would like to do is to label each source block in the > exported html with the filename used for tangling this specific block. > I don't have a strong opinion about the actual appearance of the label > (adding a comment at the top of the source block, hover in the code > textarea, other?). > > I couldn't find any option to do that, so I initially though of using > `org-export-filter-src-block-functions' (following > http://orgmode.org/manual/Advanced-configuration.html). I was not able > to get the org-element object for the current block from the parameter > received by the filter. It looks like the third parameter (`info') may > have more information but I currently don't see how to get (1) the > current source block, and (2) the tangling filename. > > I then tried to define a derived backend with custom handling of source > blocks as described in the documentation. > > I currently have the following, where I try to get the tangle filename > using `org-babel-get-src-block-info', and later insert it into the html > content using an ugly regexp. > > (defun my-html-src-block (src-block contents info) > "Transcode a SRC-BLOCK element from Org to HTML. > CONTENTS is nil. INFO is a plist used as a communication > channel." > (let* ((lang (org-element-property :language src-block)) > (src-info (org-babel-get-src-block-info t src-block)) > (tang (cdr (assq :tangle (nth 2 src-info)))) > (export-out (org-export-with-backend 'html src-block contents info)) > ) > (if (and (string= lang "lua") (and tang (> (length tang) 0))) > (progn > (let ((src-start-pat "\\(
\\)"))
>             (replace-regexp-in-string src-start-pat
>                                       (concat "\\1"
>                                               "\n-- ["
>                                               tang
>                                               "]\n\n") export-out)
>             )
>           )
>       export-out
>       )
>     )
>   )
>
> (org-export-define-derived-backend 'my-html 'html
>   :translate-alist '((src-block . my-html-src-block)))
>
> Besides feeling wrong, this always gets the tangle name from the top
> level org option ("#+PROPERTY: tangle main-file" at the top of the file)
> instead of the one overridden by individual blocks "#+BEGIN_SRC :tangle
> other-file".  Moreover the added comment is not syntax highlighted and
> this feels really wrong.
>
> Does anybody have any idea on how to achieve this?
>
> Thanks in advance.
>
> thibault