diff --git a/lisp/org-babel-tangle.el b/lisp/org-babel-tangle.el index a33849594..8115e46e1 100644 --- a/lisp/org-babel-tangle.el +++ b/lisp/org-babel-tangle.el @@ -38,13 +38,42 @@ language, and the cdr should be a list containing the extension and shebang(#!) line to use when writing out the language to file.") -(defun org-babel-tangle () +(defun org-babel-load-file (file) + "Load the contents of the Emacs Lisp source code blocks in the +org-mode formatted FILE. This function will first export the +source code using `org-babel-tangle' and then load the resulting +file using `load-file'." + (let ((loadable-file (first (org-babel-tangle-file file "emacs-lisp")))) + (message "loading %s" loadable-file) + (unless (file-exists-p loadable-file) + (error "can't load file that doesn't exist")) + (load-file loadable-file) + (message "loaded %s" loadable-file))) + +(defun org-babel-tangle-file (file &optional lang) + "Extract the bodies of all source code blocks in FILE with +`org-babel-tangle'. Optional argument LANG can be used to limit +the exported source code blocks by language." + (flet ((age (file) + (time-to-seconds + (time-subtract (current-time) + (sixth (file-attributes file)))))) + (let ((target-file (concat (file-name-sans-extension file) "." + (second (assoc lang org-babel-tangle-langs))))) + (if (and lang (file-exists-p target-file) (> (age file) (age target-file))) + (list target-file) + (save-window-excursion (find-file file) (org-babel-tangle lang)))))) + +(defun org-babel-tangle (&optional lang) "Extract the bodies of all source code blocks from the current -file into their own source-specific files." +file into their own source-specific files. Optional argument +LANG can be used to limit the exported source code blocks by +language." (interactive) (save-excursion (let ((base-name (file-name-sans-extension (buffer-file-name))) - (block-counter 0)) + (block-counter 0) + path-collector) (mapc ;; for every language create a file (lambda (by-lang) (let* ((lang (car by-lang)) @@ -54,6 +83,7 @@ file into their own source-specific files." (she-bang (second lang-specs)) (by-session (cdr by-lang))) (flet ((to-file (filename specs) + (add-to-list 'path-collector filename) (with-temp-file filename (funcall lang-f) (when she-bang (insert (concat she-bang "\n"))) @@ -69,14 +99,17 @@ file into their own source-specific files." by-session) (setq block-counter (+ block-counter (length (cdr (car by-session))))) (to-file (format "%s.%s" base-name ext) (cdr (car by-session))))))) - (org-babel-collect-blocks)) - (message "tangled %d source-code blocks" block-counter)))) + (org-babel-collect-blocks lang)) + (message "tangled %d source-code blocks" block-counter) + path-collector))) -(defun org-babel-collect-blocks () +(defun org-babel-collect-blocks (&optional lang) "Collect all source blocks in the current org-mode file. Return two nested association lists, first grouped by language, then by session, the contents will be source-code block -specifications of the form used by `org-babel-spec-to-string'." +specifications of the form used by `org-babel-spec-to-string'. +Optional argument LANG can be used to limit the collected source +code blocks by language." (let ((block-counter 0) blocks) (org-babel-map-source-blocks (buffer-file-name) (setq block-counter (+ 1 block-counter)) @@ -85,21 +118,22 @@ specifications of the form used by `org-babel-spec-to-string'." (source-name (intern (or (org-babel-get-src-block-name) (format "block-%d" block-counter)))) (info (org-babel-get-src-block-info)) - (lang (first info)) + (src-lang (first info)) (body (second info)) (params (third info)) (spec (list link source-name params body)) (session (cdr (assoc :session params))) by-lang by-session) - ;; add the spec for this block to blocks under it's lang and session - (setq by-lang (cdr (assoc lang blocks))) - (setq blocks (delq (assoc lang blocks) blocks)) - (setq by-session (cdr (assoc session by-lang))) - (setq by-lang (delq (assoc session by-lang) by-lang)) - (setq blocks (cons ;; by-language - (cons lang (cons ;; by-session - (cons session (cons spec by-session)) by-lang)) - blocks)))) + (unless (and lang (not (string= lang src-lang))) ;; maybe limit by language + ;; add the spec for this block to blocks under it's language and session + (setq by-lang (cdr (assoc src-lang blocks))) + (setq blocks (delq (assoc src-lang blocks) blocks)) + (setq by-session (cdr (assoc session by-lang))) + (setq by-lang (delq (assoc session by-lang) by-lang)) + (setq blocks (cons ;; by-language + (cons src-lang (cons ;; by-session + (cons session (cons spec by-session)) by-lang)) + blocks))))) ;; blocks should contain all source-blocks organized by language and session ;; (message "blocks=%S" blocks) ;; debugging blocks)) diff --git a/org-babel.org b/org-babel.org index d2467b70e..7d1df7564 100644 --- a/org-babel.org +++ b/org-babel.org @@ -1,5 +1,5 @@ #+TITLE: org-babel --- facilitating communication between programming languages and people -#+SEQ_TODO: TODO PROPOSED STARTED | DONE DEFERRED REJECTED +#+SEQ_TODO: PROPOSED TODO STARTED | DONE DEFERRED REJECTED #+OPTIONS: H:3 num:nil toc:t #+STARTUP: oddeven hideblocks @@ -25,11 +25,10 @@ In this document: - The [[* Sandbox][Sandbox]] :: demonstrates much of the early/basic functionality through commented source-code blocks. -Also see the [[file:library-of-babel.org][Library of Babel]] an extensible collection of ready-made +Also see the [[file:library-of-babel.org][Library of Babel]], an extensible collection of ready-made and easily-shortcut-callable source-code blocks for handling common tasks. - * Introduction Org-Babel enables *communication* between programming languages and @@ -139,7 +138,16 @@ table, allowing the test suite to be run be evaluation of the table and the results to be collected in the same table. *** Emacs initialization files stored in Org-Mode buffers -Once org-babel-tangle is completed this could be a very compelling use case. +Using `org-babel-tangle' it is possible to embed your Emacs +initialization into org-mode files. This allows for folding, +note-taking, todo's etc... embedded with the source-code of your Emacs +initialization, and through org-mode's publishing features aids in +sharing your customizations with others. + +It may be worthwhile to create a fork of Phil Hagelberg's +[[http://github.com/technomancy/emacs-starter-kit/tree/master][emacs-starter-kit]] which uses literate org-mode files for all of the +actual elisp customization. These org-mode files could then be +exported to html and used to populate the repositories wiki on [[http://github.com/][github]]. ** features @@ -191,7 +199,8 @@ would then be [[#sandbox][the sandbox]]. #+end_src -* Tasks [28/43] + +* Tasks [28/44] ** TODO support for working with =*Org Edit Src Example*= buffers [2/4] *** TODO optionally evaluate header references when we switch to =*Org Edit Src*= buffer That seems to imply that the header references need to be evaluated @@ -323,6 +332,17 @@ languages which almost always produce graphical output should set results in the buffer. Then if there is a combination of =silent= and =file= =:results= headers we could drop the results to a temp buffer and pop open that buffer... +** TODO =\C-c \C-o= to open results of source block +by adding a =defadvice= to =org-open-at-point= we can use the common +=\C-c \C-o= keybinding to open the results of a source-code block. +This would be especially useful for source-code blocks which generate +graphical results and insert a file link as the results in the +org-mode buffer. (see [[* figure out how to handle graphic output][TODO figure out how to handle graphic output]]). +This could also act reasonably with other results types... + +- file :: use org-open-at-point to open the file +- scalar :: open results unquoted in a new buffer +- tabular :: export the table to a new buffer and open that buffer ** TODO Finalise behaviour regarding vector/scalar output *** DONE Stop spaces causing vector output @@ -823,8 +843,41 @@ $0 [[file:snippets/org-mode/sb][sb -- snippet]] waiting for guidance from those more familiar with yasnippets - ** DONE LoB: allow output in buffer +** DONE singe-function tangling and loading elisp from literate org-mode file [3/3] + +This function should tangle the org-mode file for elisp, and then call +`load-file' on the resulting tangled file. + +#+srcname: test-loading-embedded-emacs-lisp +#+begin_src emacs-lisp :results replace + (setq test-tangle-advert nil) + (setq test-tangle-loading nil) + (setq results (list :before test-tangle-loading test-tangle-advert)) + (org-babel-load-file "test-tangle.org") + (setq results (list (list :after test-tangle-loading test-tangle-advert) results)) + (delete-file "test-tangle.el") + (reverse results) +#+end_src + +#+resname: test-loading-embedded-emacs-lisp +| :before | nil | nil | +| :after | "org-babel tangles" | "use org-babel-tangle for all your emacs initialization files!!" | + +*** DONE add optional language limiter to org-babel-tangle +This should check to see if there is any need to re-export + +*** DONE ensure that org-babel-tangle returns the path to the tangled file(s) + +#+srcname: test-return-value-of-org-babel-tangle +#+begin_src emacs-lisp :results replace + (mapcar #'file-name-nondirectory (org-babel-tangle-file "test-tangle.org" "emacs-lisp")) +#+end_src + +#+resname: +| "test-tangle.el" | + +*** DONE only tangle the file if it's actually necessary ** DONE add a function to jump to a source-block by name I've had an initial stab at that in org-babel-find-named-block (library-of-babel branch). @@ -1914,20 +1967,11 @@ This could probably be added to [[file:lisp/org-babel-script.el][org-babel-scrip (see [[* file result types][file result types]]) -* Bugs [17/28] +* Bugs [18/23] ** TODO Allow source blocks to be recognised when #+ are not first characters on the line I think Carsten has recently altered the core so that #+ can have preceding whitespace, at least for literal/code examples. org-babel should support this. -** PROPOSED make :results replace the default? - I'm tending to think that appending results to pre-existing results - creates mess, and that the cleaner `replace' option should be the - default. E.g. when a source block creates an image, we would want - that to be updated, rather than have a new one be added. -** PROPOSED external shell execution can't isolate return values -I have no idea how to do this as of yet. The result is that when -shell functions are run w/o a session there is no difference between -the =output= and =value= result arguments. ** TODO non-orgtbl formatted lists for example @@ -1939,10 +1983,11 @@ for example #+resname: this-doesn't-match-orgtbl + ** TODO collapsing consecutive newlines in string output #+srcname: multi-line-string-output -#+begin_src ruby :results replace +#+begin_src ruby :results output "the first line ends here @@ -1951,15 +1996,35 @@ for example even a third" #+end_src -#+resname: -: the first line ends here -: and this is the second one -: return even a third +#+resname: multi-line-string-output + ** TODO cursor movement when evaluating source blocks E.g. the pie chart example. Despite the save-window-excursion in org-babel-execute:R. (I never learned how to do this properly: org-R jumps all over the place...) + +** PROPOSED external shell execution can't isolate return values +I have no idea how to do this as of yet. The result is that when +shell functions are run w/o a session there is no difference between +the =output= and =value= result arguments. + +Yea, I don't know how to do this either. I searched extensively on +how to isolate the *last* output of a series of shell commands (see +[[* last command for + shells][last command for shells]]). The results of the search were basically +that it was not possible (or at least not accomplish-able with a +reasonable amount of effort). + +That fact combined with the tenancy to all ways use standard out in +shell scripts led me to treat these two options (=output= and =value=) +as identical in shell evaluation. Not ideal but maybe good enough for +the moment. + +In the `results' branch I've changed this so that they're not quite +identical: output results in raw stdout contents, whereas value +converts it to elisp, perhaps to a table if it looks tabular. This is +the same for the other languages. [Dan] ** TODO are the org-babel-trim s necessary? at the end of e.g. org-babel-R-evaluate, org-babel-python-evaluate, but @@ -2045,6 +2110,15 @@ even a third" | 6 | .1666 | #+lob: R-plot(data=XX) + +** DONE make :results replace the default? + I'm tending to think that appending results to pre-existing results + creates mess, and that the cleaner `replace' option should be the + default. E.g. when a source block creates an image, we would want + that to be updated, rather than have a new one be added. + + I agree. + ** DONE ruby evaluation not working under ubuntu emacs 23 With emacs 23.0.91.1 on ubuntu, for C-h f run-ruby I have the following, which seems to conflict with [[file:lisp/langs/org-babel-ruby.el::let%20session%20buffer%20save%20window%20excursion%20run%20ruby%20nil%20session%20current%20buffer][this line]] in org-babel-ruby.el. @@ -2775,13 +2849,6 @@ table.first.join(" - ") table[0] #+end_src -#+resname: -: [1, 2, 3] - - - - -| 1 | 2 | 3 | #+begin_src ruby :var table=sandbox :results replace table diff --git a/test-tangle.org b/test-tangle.org index b8e965996..2f08f109b 100644 --- a/test-tangle.org +++ b/test-tangle.org @@ -76,3 +76,12 @@ end #+begin_src ruby :session special plus_two(holder) #+end_src + + +** Emacs Lisp initialization stuff + +#+srcname: lets-set-some-variables +#+begin_src emacs-lisp + (setq test-tangle-loading "org-babel tangles") + (setq test-tangle-advert "use org-babel-tangle for all your emacs initialization files!!") +#+end_src