emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Extract source code /with/ captions
@ 2014-01-12 14:49 James Harkins
  2014-01-12 17:19 ` John Kitchin
  2014-01-12 18:34 ` Charles Berry
  0 siblings, 2 replies; 9+ messages in thread
From: James Harkins @ 2014-01-12 14:49 UTC (permalink / raw)
  To: Emacs-orgmode@gnu.org

I'm working on a set of Beamer presentations with a bunch of source
code blocks. I would like to collect all the blocks into one text file
per presentation, but I also need the captions and ideally a numeric
index.

That is, I'm *not* looking for the normal behavior of
org-babel-tangle, which assembles only the source code itself without
any other identifying information (on the assumption that the tangled
file should be OK to be compiled). These code blocks are not part of
one big program. They are examples that workshop participants should
run interactively.

So, for instance, where the slideshow and handouts would have a code
block identified like so:

Listing 3: Compare geometric vs. band-limited waves, aurally.

... a student should be able to open up the corresponding code file and find:

// Listing 3: Compare geometric vs. band-limited waves, aurally.

Just wondering if anyone has done this. If not, I'm sure I can hack
something up but it would save some time if somebody has some code
lying around.

Thanks in advance --
hjh

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-12 14:49 Extract source code /with/ captions James Harkins
@ 2014-01-12 17:19 ` John Kitchin
  2014-01-13  2:52   ` James Harkins
  2014-01-12 18:34 ` Charles Berry
  1 sibling, 1 reply; 9+ messages in thread
From: John Kitchin @ 2014-01-12 17:19 UTC (permalink / raw)
  To: jamshark70; +Cc: Emacs-orgmode@gnu.org

[-- Attachment #1: Type: text/plain, Size: 3368 bytes --]

I think I have done something like that before. What I did was make it so
each code block would be written out to a file, e.g.
course-notes/script-%d.py and a link would be put in the exported pdf right
after that block. I do not know how you could get the captions though.

In the header I have this:
#+LATEX_HEADER: \newcommand{\LaunchBinary}[2]{%
#+LATEX_HEADER:   % #1: layer name,
#+LATEX_HEADER:   % #2: link text
#+LATEX_HEADER:   \leavevmode%
#+LATEX_HEADER:   \pdfstartlink  attr{/C [0.9 0 0] /Border [0 0 2]} user {
#+LATEX_HEADER:     /Subtype /Link
#+LATEX_HEADER:     /A <<
#+LATEX_HEADER:       /F <<
#+LATEX_HEADER:          /DOS (#1)
#+LATEX_HEADER:          /Mac (#1)
#+LATEX_HEADER:          /Unix (#1)
#+LATEX_HEADER:       >>
#+LATEX_HEADER:       /S /Launch
#+LATEX_HEADER:     >>
#+LATEX_HEADER:   } #2%
#+LATEX_HEADER:   \pdfendlink%
#+LATEX_HEADER: }

Then this code for the export. (I pasted it from my build file, so there
may be an extra parenthesis at the end)

(setq counter 0)

  (defun ox-mrkup-filter-src-block (text back-end info)
    (setq counter (+ counter 1))

    (let ((filename (format "course-notes-scripts/script-%d.py" counter)))
      (with-temp-buffer
        (insert (mapconcat 'identity (butlast (cdr (split-string text "\n"
t))) "\n"))
        (write-region (point-min) (point-max) filename))

      (format "%s

\\LaunchBinary{%s}{Open the python script (%s).}

" text filename filename)))

(let ((org-export-filter-src-block-functions '(ox-mrkup-filter-src-block)))
  (org-latex-export-to-latex async subtreep visible-only body-only
                 '(:with-author t
                                            :with-date t
                                            :with-title t
                                            :with-timestamps t
                                            :with-todo-keywords t
                                            :with-toc nil))))

maybe that is close to what you want?

John

-----------------------------------
John Kitchin
Associate Professor
Doherty Hall A207F
Department of Chemical Engineering
Carnegie Mellon University
Pittsburgh, PA 15213
412-268-7803
http://kitchingroup.cheme.cmu.edu



On Sun, Jan 12, 2014 at 9:49 AM, James Harkins <jamshark70@gmail.com> wrote:

> I'm working on a set of Beamer presentations with a bunch of source
> code blocks. I would like to collect all the blocks into one text file
> per presentation, but I also need the captions and ideally a numeric
> index.
>
> That is, I'm *not* looking for the normal behavior of
> org-babel-tangle, which assembles only the source code itself without
> any other identifying information (on the assumption that the tangled
> file should be OK to be compiled). These code blocks are not part of
> one big program. They are examples that workshop participants should
> run interactively.
>
> So, for instance, where the slideshow and handouts would have a code
> block identified like so:
>
> Listing 3: Compare geometric vs. band-limited waves, aurally.
>
> ... a student should be able to open up the corresponding code file and
> find:
>
> // Listing 3: Compare geometric vs. band-limited waves, aurally.
>
> Just wondering if anyone has done this. If not, I'm sure I can hack
> something up but it would save some time if somebody has some code
> lying around.
>
> Thanks in advance --
> hjh
>
>

[-- Attachment #2: Type: text/html, Size: 4214 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-12 14:49 Extract source code /with/ captions James Harkins
  2014-01-12 17:19 ` John Kitchin
@ 2014-01-12 18:34 ` Charles Berry
  1 sibling, 0 replies; 9+ messages in thread
From: Charles Berry @ 2014-01-12 18:34 UTC (permalink / raw)
  To: emacs-orgmode

James Harkins <jamshark70 <at> gmail.com> writes:

> 
> I'm working on a set of Beamer presentations with a bunch of source
> code blocks. I would like to collect all the blocks into one text file
> per presentation, but I also need the captions and ideally a numeric
> index.
> 

[deleted]

> So, for instance, where the slideshow and handouts would have a code
> block identified like so:
> 
> Listing 3: Compare geometric vs. band-limited waves, aurally.
> 
> ... a student should be able to open up the corresponding code file and find:
> 
> // Listing 3: Compare geometric vs. band-limited waves, aurally.
> 

Can you make the 'caption' into a heading?

If so, then ':comments org' will include it in output when you tangle.

Or maybe ':comments link' or ':comments both' and some post-processing?

HTH,

Chuck

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-12 17:19 ` John Kitchin
@ 2014-01-13  2:52   ` James Harkins
  2014-01-13 17:06     ` Nick Dokos
  0 siblings, 1 reply; 9+ messages in thread
From: James Harkins @ 2014-01-13  2:52 UTC (permalink / raw)
  To: John Kitchin; +Cc: Emacs-orgmode

On Monday, January 13, 2014 1:19:28 AM HKT, John Kitchin wrote:
> I think I have done something like that before. What I did was make it so
> each code block would be written out to a file, e.g.
> course-notes/script-%d.py and a link would be put in the exported pdf 
right
> after that block. I do not know how you could get the captions though.

Thanks for the suggestion. I think it might be overkill for my case. One 
thing is, I don't need links in the LaTeX output -- hence, no need to tie 
it to LaTeX export.

So, after a night's sleep, I remembered something about org-element and 
took a look at some docstrings. A clever comment about "The (almost) 
almighty `org-element-map'" attracted particular attention :)  and indeed, 
it turns out that it does almost all the hard work.

Some progress, then:

(defun hjh-print-src-blocks ()
  "Iterate src blocks from org-element and print them to *Messages*."
  (interactive)
  (let ((tree (org-element-parse-buffer)))
    (org-element-map tree 'src-block
      (lambda (element)
	(message "\n\n\nELEMENT:")
	(print (plist-get (car (cdr element)) :caption))))))

I pulled one frame with two src blocks out of the presentation, put it in a 
separate file, and running this function from the buffer produces this in 
the messages buffer (omitting some blank lines, which I had inserted while 
running this under edebug):

ELEMENT:
(((#("25% coin toss in SmallTalk" 0 26 (:parent #2)))))

ELEMENT:
(((#("25% coin toss in SuperCollider" 0 30 (:parent #2)))))

This is correct, and I also see that I can use (plist-get ... :value) to 
get the code string.

Here, I'm hung up on some (large?) gaps in my elisp knowledge. I have no 
idea what #(...) signifies, or what functions I can use to get the string 
out of it. "#" Is not an especially useful search term in google, bing 
etc...

Can anyone help with my next step?

Also, big thanks to Nicolas for org-element. The fact that an elisp novice 
can extract captions for source blocks in about half an hour of tinkering 
is nothing short of criminally easy. Spectacular.

hjh

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-13  2:52   ` James Harkins
@ 2014-01-13 17:06     ` Nick Dokos
  2014-01-13 17:46       ` Nick Dokos
  2014-01-13 18:01       ` Nick Dokos
  0 siblings, 2 replies; 9+ messages in thread
From: Nick Dokos @ 2014-01-13 17:06 UTC (permalink / raw)
  To: emacs-orgmode

James Harkins <jamshark70@gmail.com> writes:

> ELEMENT:
> (((#("25% coin toss in SuperCollider" 0 30 (:parent #2)))))
>
> This is correct, and I also see that I can use (plist-get ... :value)
> to get the code string.
>
> Here, I'm hung up on some (large?) gaps in my elisp knowledge. I have
> no idea what #(...) signifies, or what functions I can use to get the
> string out of it. "#" Is not an especially useful search term in
> google, bing etc...
>
> Can anyone help with my next step?
>

Not sure whether this will help but these are basically just strings
with text properties. See

     (info "(elisp) Text Properties in Strings")

> Also, big thanks to Nicolas for org-element. The fact that an elisp
> novice can extract captions for source blocks in about half an hour of
> tinkering is nothing short of criminally easy. Spectacular.
>
Oh, yes indeed!

Nick

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-13 17:06     ` Nick Dokos
@ 2014-01-13 17:46       ` Nick Dokos
  2014-01-13 18:01       ` Nick Dokos
  1 sibling, 0 replies; 9+ messages in thread
From: Nick Dokos @ 2014-01-13 17:46 UTC (permalink / raw)
  To: emacs-orgmode

Nick Dokos <ndokos@gmail.com> writes:

> James Harkins <jamshark70@gmail.com> writes:
>
>> ELEMENT:
>> (((#("25% coin toss in SuperCollider" 0 30 (:parent #2)))))
>>
>> This is correct, and I also see that I can use (plist-get ... :value)
>> to get the code string.
>>
>> Here, I'm hung up on some (large?) gaps in my elisp knowledge. I have
>> no idea what #(...) signifies, or what functions I can use to get the
>> string out of it. "#" Is not an especially useful search term in
>> google, bing etc...
>>
>> Can anyone help with my next step?
>>
>
> Not sure whether this will help but these are basically just strings
> with text properties. See
>
>      (info "(elisp) Text Properties in Strings")
>

I should have added:

o You can use substring-no-properties on a string to just get the
  sequence of characters it consists of without its text properties[fn:1]

--8<---------------cut here---------------start------------->8---
(setq s #("25% coin toss in SuperCollider" 0 30 (face bold)))
(substring-no-properties s) ==> "25% coin toss in SuperCollider"
--8<---------------cut here---------------end--------------->8---

o You can similarly use (buffer-substring-no-properties START END) if
  you want to extract a substring out of a buffer without its text
  properties.

Footnotes:
[fn:1] Note that I had to modify the properties a bit to make it into
       a string that the lisp reader could grok. When you print out the
       element, you get a shorthand representation of it:

       #("25% coin toss in SuperCollider" 0 30 (:parent #2))

       indicating the parent, but #2 is not legal as far as the lisp reader
       is concerned - it is just a useful shorthand for humans; however
       when you map your function on what org-element-parse-buffer
       returns, calling substring-no-properties on it before you print
       it (or whatever else you want to do to it) will do the right
       thing (modulo bugs of course).

Nick
        
       

      
      
       
       

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-13 17:06     ` Nick Dokos
  2014-01-13 17:46       ` Nick Dokos
@ 2014-01-13 18:01       ` Nick Dokos
  2014-01-18  2:20         ` James Harkins
  1 sibling, 1 reply; 9+ messages in thread
From: Nick Dokos @ 2014-01-13 18:01 UTC (permalink / raw)
  To: emacs-orgmode

[I sent a follow-up that has not shown up yet(?) but
 perhaps this is more useful in any case]

James Harkins <jamshark70@gmail.com> writes:

> ELEMENT:
> (((#("25% coin toss in SuperCollider" 0 30 (:parent #2)))))
>
> This is correct, and I also see that I can use (plist-get ... :value)
> to get the code string.
>
> Here, I'm hung up on some (large?) gaps in my elisp knowledge. I have
> no idea what #(...) signifies, or what functions I can use to get the
> string out of it. "#" Is not an especially useful search term in
> google, bing etc...
>
> Can anyone help with my next step?
>
 
Try:

--8<---------------cut here---------------start------------->8---
 (defun hjh-print-src-blocks ()
 "Iterate src blocks from org-element and print them to *Messages*."
 (interactive)
 (let ((tree (org-element-parse-buffer)))
   (org-element-map tree 'src-block
     (lambda (element)
	(message "\n\n\nELEMENT:")
	(print (substring-no-properties (plist-get (car (cdr element)) :caption)))))))
--8<---------------cut here---------------end--------------->8---

Nick

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-13 18:01       ` Nick Dokos
@ 2014-01-18  2:20         ` James Harkins
  2014-01-18  3:04           ` James Harkins
  0 siblings, 1 reply; 9+ messages in thread
From: James Harkins @ 2014-01-18  2:20 UTC (permalink / raw)
  To: emacs-orgmode

Nick Dokos <ndokos <at> gmail.com> writes:

> Try:
> 
> --8<---------------cut here---------------start------------->8---
>  (defun hjh-print-src-blocks ()
>  "Iterate src blocks from org-element and print them to *Messages*."
>  (interactive)
>  (let ((tree (org-element-parse-buffer)))
>    (org-element-map tree 'src-block
>      (lambda (element)
> 	(message "\n\n\nELEMENT:")
> 	(print (substring-no-properties (plist-get (car (cdr element))
:caption)))))))
> --8<---------------cut here---------------end--------------->8---

Finally coming back to this.

It seems that the actual string-with-properties may be nested at different
levels within the :caption object. I tried Nick's version with a different
test file, and it failed with a wrong type error.

The "while" below seems to work, though I suppose it could throw an error
under some circumstances.

Is there an easier way to locate the real stringy-thingy in the middle of
the structure, when you can't predict exactly what the structure will be?

(defun hjh-print-src-blocks ()
  "Iterate src blocks from org-element and print them to *Messages*."
  (interactive)
  (let ((tree (org-element-parse-buffer)))
    (org-element-map tree 'src-block
      (lambda (element)
	(setq element (car (cdr element)))
	(let ((caption (plist-get element :caption)))
	  (while (and caption (not (stringp caption)))
	    (setq caption (car caption)))
	  (message "\n\n\nCAPTION:")
	  (print (substring-no-properties caption)))))))

hjh

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Extract source code /with/ captions
  2014-01-18  2:20         ` James Harkins
@ 2014-01-18  3:04           ` James Harkins
  0 siblings, 0 replies; 9+ messages in thread
From: James Harkins @ 2014-01-18  3:04 UTC (permalink / raw)
  To: emacs-orgmode

For posterity, this is doing what I want.

It's with some shock that I note, I'm actually starting to understand LISP.

hjh


(defun hjh-get-string-from-nested-thing (thing)
  "Peel off 'car's from a nested list until the car is a string."
  (while (and thing (not (stringp thing)))
    (setq thing (car thing)))
  thing
)

(defun hjh-src-blocks-to-string ()
  "Iterate src blocks from org-element and add them to a string."
  (interactive)
  (let ((tree (org-element-parse-buffer))
	(string "")
	(counter 0))
    (org-element-map tree 'src-block
      (lambda (element)
	(setq element (car (cdr element)))
	(let ((caption (hjh-get-string-from-nested-thing (plist-get element :caption)))
	      (source (hjh-get-string-from-nested-thing (plist-get element :value))))
	  (when caption
	    (setq counter (1+ counter))
	    (setq string (concat string (format "/*********
Listing %d. %s
 *********/

%s\n\n"
					  counter
					  (substring-no-properties caption)
					  (substring-no-properties source))))))))
    string))

(defun hjh-src-blocks-to-buffer ()
  "Put all the captioned source blocks from a buffer into another buffer."
  (interactive)
  (let* ((contents (hjh-src-blocks-to-string))
	 (bufpath (buffer-file-name))
	 (newname (concat (file-name-sans-extension bufpath) ".scd"))
	 (bufname (file-name-nondirectory newname))
	 (newbuf (get-buffer-create bufname)))
    (with-current-buffer newbuf
      (erase-buffer)
      (insert contents)
      (set-visited-file-name newname))
    (switch-to-buffer-other-window newbuf)))

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-01-18  3:04 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-12 14:49 Extract source code /with/ captions James Harkins
2014-01-12 17:19 ` John Kitchin
2014-01-13  2:52   ` James Harkins
2014-01-13 17:06     ` Nick Dokos
2014-01-13 17:46       ` Nick Dokos
2014-01-13 18:01       ` Nick Dokos
2014-01-18  2:20         ` James Harkins
2014-01-18  3:04           ` James Harkins
2014-01-12 18:34 ` Charles Berry

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).