From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Kitchin Subject: Re: Feature suggestion and code review request: org-babel-cycle-src-block-header Date: Sun, 4 Mar 2018 15:09:19 -0800 Message-ID: References: <87muztqt1b.fsf@gmail.com> <87d10l9bse.fsf@gmail.com> <878tb8aos1.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="089e082f38c4abeee905669e4cad" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:44121) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1esckw-0001LP-1y for emacs-orgmode@gnu.org; Sun, 04 Mar 2018 18:09:29 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1escks-0003bA-Om for emacs-orgmode@gnu.org; Sun, 04 Mar 2018 18:09:26 -0500 Received: from mail-wm0-x236.google.com ([2a00:1450:400c:c09::236]:56043) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1escks-0003ar-7x for emacs-orgmode@gnu.org; Sun, 04 Mar 2018 18:09:22 -0500 Received: by mail-wm0-x236.google.com with SMTP id q83so12503155wme.5 for ; Sun, 04 Mar 2018 15:09:21 -0800 (PST) In-Reply-To: <878tb8aos1.fsf@gmail.com> 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: Thorsten Jolitz Cc: org-mode-email --089e082f38c4abeee905669e4cad Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Thanks for the examples. There is an interesting issue, the following does not save-excursion! (save-excursion (org-dp-rewire 'src-block t t ;cont ins t ;aff nil ;elem :parameters ":results output")) The point gets moved. Do you know why that happens? John ----------------------------------- Professor John Kitchin Doherty Hall A207F Department of Chemical Engineering Carnegie Mellon University Pittsburgh, PA 15213 412-268-7803 @johnkitchin http://kitchingroup.cheme.cmu.edu On Sat, Mar 3, 2018 at 12:26 PM, Thorsten Jolitz wrote: > Thorsten Jolitz writes: > > PS > One more to show that one can not only easily modify a certain > org element, but that its just as easy to convert it to another type of > org element. > > Use this (call M-x tj/obch) > > #+BEGIN_SRC emacs-lisp > (defun tj/obch () > "docstring" > (interactive) > (org-dp-rewire 'example-block t t ;cont ins > '(:caption (("val2" "key2") ("val2" "key2")) > :attr_xyz ("val1" "val2")) ;aff > nil ;elem > :language "common-lisp" > :switches '(lambda (old elem) old ) > :parameters 'tj/toggle-params > :value '(lambda (old elem) > (let ((old1 > (string-remove-suffix "\n" old))) > (concat "(+ 3 " old1 " 17)\n"))) > :preserve-indent '(lambda (old elem) old ) ) ) > #+END_SRC > > with point on this source block header > > ,---- > | * test > | > | #+NAME: test1 > | #+BEGIN_SRC emacs-lisp :tangle yes :results none > | (+ 1 1) > | #+END_SRC > `---- > > to get this > > ,---- > | #+NAME: test1 > | #+CAPTION[key2]: val2 > | #+CAPTION[key2]: val2 > | #+ATTR_XYZ: val2 > | #+ATTR_XYZ: val1 > | #+BEGIN_EXAMPLE > | (+ 3 (+ 1 1) 17) > | #+END_EXAMPLE > `---- > > > > > > John Kitchin writes: > > > > Hallo, > > > >> This is a neat idea. > > > > This is quite a nice use/show case for org-dp too. > > > > I did not really try to solve the users feature request, just wanted to > > demonstrate how different a possible solution looks using declarative > > programming, leaving all the low-level parsing and interpreting work to > > the org-element framework. > > > > 1. Example org-mode buffer > > > > ,---- > > | * test > > | > > | #+NAME: test1 > > | #+BEGIN_SRC emacs-lisp :tangle yes :results none > > | (+ 1 1) > > | #+END_SRC > > | > > | #+NAME: test2 > > | #+BEGIN_SRC picolisp :tangle no :results raw > > | (+ 2 2) > > | #+END_SRC > > `---- > > > > 2. Elisp to toggle the parameter values > > > > The org-dp part is this. > > > > Call the mapping cmd (M-x tj/obch-map) in the buffer (act on all > > src-blocks), or put point on a src-block header and call M-x tj/obch to > > just act on that scr-block. > > > > ,---- > > | (defun tj/obch () > > | "docstring" > > | (interactive) > > | (org-dp-rewire 'src-block t t ;cont ins > > | t ;aff > > | nil ;elem > > | :language '(lambda (old elem) old ) > > | :switches '(lambda (old elem) old ) > > | :parameters 'tj/toggle-params > > | :value '(lambda (old elem) old ) > > | :preserve-indent '(lambda (old elem) old ) ) ) > > | > > | > > | (defun tj/obch-map () > > | "docstring" > > | (interactive) > > | (org-dp-map '(tj/obch) "#\\+BEGIN_SRC")) > > `---- > > > > You can play around with the other args to org-dp-rewire (apart from > > :parameters) to find out how easy you can change (or remove/add) other > > parts of the src-block without any work on the textual representation. > > > > E.g. try this: > > > > #+BEGIN_SRC emacs-lisp > > (defun tj/obch () > > "docstring" > > (interactive) > > (org-dp-rewire 'src-block t t ;cont ins > > nil ;aff > > nil ;elem > > :language "common-lisp" > > :switches '(lambda (old elem) old ) > > :parameters 'tj/toggle-params > > :value '(lambda (old elem) > > (let ((old1 > > (string-remove-suffix "\n" old))) > > (concat "(+ 3 " old1 " 17)\n"))) > > :preserve-indent '(lambda (old elem) old ) ) ) > > #+END_SRC > > > > > > to see this result in the example buffer after calling M-x tj/obch-map: > > > > ,---- > > | * test > > | > > | #+BEGIN_SRC common-lisp :tangle no :results raw > > | (+ 3 (+ 1 1) 17) > > | #+END_SRC > > | > > | #+BEGIN_SRC common-lisp :tangle yes :results none > > | (+ 3 (+ 2 2) 17) > > | #+END_SRC > > `---- > > > > PS > > Here is the whole code. > > The logic in 'tj/toggle-params is not really of interest here. The > > important thing is, that all of these options are possible: > > > > - simply assign a value > > - implement a lambda function in place (with two args) > > - implement a named function (with two args) and use its name > > > > ,---- > > | :parameters ":tangle no" > > | :parameters '(lambda (old elem) (concat old " :results none") ) > > | :parameters 'tj/toggle-params > > `---- > > > > #+BEGIN_SRC emacs-lisp > > (defvar tj/change-p) > > > > ;; org-dp in action > > ;; wrap org-dp-rewire in utility cmd for readability > > (defun tj/obch () > > "docstring" > > (interactive) > > (org-dp-rewire 'src-block t t ;cont ins > > t ;aff > > nil ;elem > > :language '(lambda (old elem) old ) > > :switches '(lambda (old elem) old ) > > :parameters 'tj/toggle-params > > :value '(lambda (old elem) old ) > > :preserve-indent '(lambda (old elem) old ) ) ) > > > > > > (defun tj/obch-map () > > "docstring" > > (interactive) > > (org-dp-map '(tj/obch) "#\\+BEGIN_SRC")) > > > > ;; helper functions for this use case, not really of interest > > ;; toggle src-block parameter values > > (defun tj/toggle-params (old elem) > > "docstring" > > (let* ((params-lst (split-string old))) > > (setq tj/change-p nil) > > (mapconcat 'tj/replace-vals params-lst " ")) ) > > > > ;; helper functon to actually replace old with new values > > (defun tj/replace-vals (strg) > > "docstring" > > (let (res) > > (if tj/change-p > > (progn > > (cond > > ((string-equal strg "yes") > > (setq res "no")) > > ((string-equal strg "no") > > (setq res "yes")) > > ((string-equal strg "none") > > (setq res "raw")) > > ((string-equal strg "raw") > > (setq res "none")) ) > > (setq tj/change-p nil) > > res) > > (cond > > ((string-equal strg ":tangle") > > (setq tj/change-p t)) > > ((string-equal strg ":results") > > (setq tj/change-p t))) > > strg))) > > #+END_SRC > > > > > >> I sometimes want to switch to silent, or between > >> value and results. I don't know if you would consider the code below a= n > >> improvement, but it seems to do what you want, and is shorter. It has > >> less checking of things, and is more of a replace the header kind of > >> approach. > >> > >> Personally, I think strings are the way to go here. > >> > >> #+BEGIN_SRC emacs-lisp :tangle yes :results none > >> (require 's) > >> (require 'dash) > >> > >> (defvar header-sequences '((emacs-lisp . (":tangle no :results none" ;= ; > >> type 2 above > >> ":tangle yes :results none" ;; type 3 above > >> ":results type verbatim" ;; type 1 above > >> )))) > >> > >> (defun obch () > >> (interactive) > >> (let* ((lang (car (org-babel-get-src-block-info t))) > >> (headers (cdr (assoc (intern-soft lang) header-sequences))) > >> header index) > >> (save-excursion > >> (org-babel-goto-src-block-head) > >> (re-search-forward lang) > >> (setq header (buffer-substring-no-properties (point) > >> (line-end-position)) > >> index (-find-index (lambda (s) (string=3D (s-trim s) (s-trim header))) > >> headers)) > >> (delete-region (point) (line-end-position)) > >> (insert " " (if index > >> (nth (mod (+ 1 index) (length headers)) headers) > >> (car headers)))))) > >> #+END_SRC > >> > >> John > >> > >> ----------------------------------- > >> Professor John Kitchin > >> Doherty Hall A207F > >> Department of Chemical Engineering > >> Carnegie Mellon University > >> Pittsburgh, PA 15213 > >> 412-268-7803 > >> @johnkitchin > >> http://kitchingroup.cheme.cmu.edu > >> > >> On Wed, Feb 28, 2018 at 2:59 AM, Akater wrote= : > >> > >> When I have a chance, I enjoy the following development workflow: > >> the > >> code is written in org files and is tangled into conventional source > >> code files more or less regularly. > >> > >> I find that source blocks mostly fall into three categories, > >> numbered > >> here for further reference: > >> - examples/test cases/desiderata, like > >> `(my-implemented-or-desired-function x y)' (type 1) > >> - drafts, failed attempts at implementations and other snippets > >> better > >> left as is, or as a warning (type 2) > >> - working implementations, to be tangled (type 3) > >> > >> Hence I end up using only a handful of header argument strings. An > >> example corresponding to this 3-cases setup is found below. So it > >> would > >> be nice to have a function that cycles between those, much like we > >> can > >> cycle through org TODO sequence now using a standard function, and > >> set > >> up this sequence per Org file. > >> > >> I'm fairly bad at Emacs Lisp, so I'm interested in feedback about my > >> implementation of cycling function. It operates with strings, mostly > >> because I failed to make it work with lists of alists of header > >> arguments as ob-core.el suggests. On the other hand, given that > >> Emacs > >> Lisp is more string-oriented than it is object-oriented, it might > >> not be > >> a really bad idea. > >> > >> So what do you think? How can this implementation be improved? (Sans > >> using rotate and tracking position in a smarter way.) Does it make > >> sense > >> to include this feature in Org mode? Maybe I missed some existing > >> well-estabilished solutions? This is something akin to =E2=80=9Cliter= ate > >> programming=E2=80=9D; I'm not a fan of this idea---at least the way i= t is > >> usually presented---but it is somewhat popular a topic. I have some > >> other feature in mind I'd love to see implemented in Org-Babel: > >> convenient export of src blocks of type 1 (see above) into unit > >> tests > >> (as test cases) and into documentation sources (as examples) but > >> this > >> one is heavily target-language dependent and probably deserves its > >> own > >> thread. > >> > >> #+begin_src emacs-lisp > >> (cl-defun next-maybe-cycled (elem list &key (test #'equal)) > >> "Returns the element in `list' next to the first `elem' found. If > >> `elem' is found at `list''s very tail, returns `list''s car. > >> `next-maybe-cycled' provides no way to distinguish between \"found > >> nil\" and \"found nothing\"." > >> (let ((sublist (cl-member elem list :test test))) > >> (and sublist > >> (if (cdr sublist) > >> (cadr sublist) > >> (car list))))) > >> > >> (defun shrink-whitespace (string) > >> "Transforms all whitespace instances into single spaces. Trims > >> whitespace at beginning and end. No argument type checking." > >> (cl-reduce (lambda (string rule) > >> (replace-regexp-in-string (car rule) (cdr rule) string)) > >> '(("[[:blank:]]+" . " ") ("^[[:blank:]]*" . "") ("[[:blank:]]*$" . > >> "")) > >> :initial-value string)) > >> > >> (defun string-equal-modulo-whitespace (x y) > >> (string-equal (shrink-whitespace x) (shrink-whitespace y))) > >> > >> (defun org-babel-cycle-src-block-header-string (header-strings) > >> "Cycle through given `header-strings' if currently in Org Babel > >> source code block. If current src-block header is not found in > >> `header-strings', switch header to the car of `header-strings'. > >> > >> `header-strings' must be a non-empty list of strings. All whitespace > >> in them is shrinked. > >> > >> If UNDO-ed, cursor position is not guaranteed to be preserved." > >> (interactive) > >> (cond > >> ((not (and header-strings (listp header-strings))) > >> (error "No Org Babel header strings list found to cycle through. %S > >> found intstead." header-strings)) > >> ((not (every #'stringp header-strings)) > >> (error "Malformed list of Org Babel header strings: not all elements > >> are strings in %S." header-strings)) > >> (t > >> (let ((initial-position (point))) > >> (org-babel-goto-src-block-head) > >> ;; here we rely on `org-babel-goto-src-block-head' > >> ;; signalling an error if not in source code block > >> (forward-char (length "#+BEGIN_SRC")) > >> (let* ((fallback-position (point)) > >> (we-were-before-replacement-zone (<=3D initial-position > >> fallback-position))) > >> (let ((default-position-to-return-to initial-position) > >> (old-header-string (delete-and-extract-region (point) > >> (line-end-position)))) > >> (unless we-were-before-replacement-zone > >> (incf default-position-to-return-to (- (length old-header-string)))) > >> (let ((new-header-string > >> (concatenate 'string > >> " " > >> (shrink-whitespace > >> (or (next-maybe-cycled old-header-string > >> header-strings > >> :test #'string-equal-modulo-whitespace) > >> (car header-strings)))))) > >> (insert new-header-string) > >> (unless we-were-before-replacement-zone > >> (incf default-position-to-return-to (length new-header-string))) > >> (goto-char (if (<=3D fallback-position > >> default-position-to-return-to > >> (+ fallback-position (length new-header-string))) > >> fallback-position > >> default-position-to-return-to))))))))) > >> > >> ;; example for mailing list > >> ;; Common Lisp assumed! > >> (defun akater/org-babel-cycle-header nil > >> (interactive) > >> (org-babel-cycle-src-block-header-string > >> '("lisp :tangle no :results none" ;; type 2 above > >> "lisp :tangle yes :results none" ;; type 3 above > >> "lisp :results type verbatim" ;; type 1 above > >> ))) > >> #+end_src > >> > >> Ideally, I envision something along these lines (some specific > >> choices > >> below don't really make sense): > >> #+begin_src emacs-lisp > >> (defcustom org-babel-standard-header-sequences-alist > >> '((development-setup-1 > >> (lisp > >> (((:tangle . "no") > >> (:results . "none")) > >> ((:tangle . "yes") > >> (:results . "none")) > >> ((:results . "type verbatim")))) > >> (python > >> (((:tangle . "no") > >> (:results . "none")) > >> ((:tangle . "yes") > >> (:results . "none")) > >> ((:results . "type output")))) > >> ) > >> (development-setup-2 > >> (C > >> (((:tangle . "no") > >> (:results . "none")) > >> ((:tangle . "yes") > >> (:results . "raw")))) > >> (julia > >> (((:tangle . "no") > >> (:results . "none")) > >> ((:tangle . "yes") > >> (:results . "none"))))))) > >> #+end_src > >> > >> > > -- > cheers, > Thorsten > > > --089e082f38c4abeee905669e4cad Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Thanks for the examples.

There is an in= teresting issue, the following does not save-excursion!

<= div>
(save-excursion
=C2=A0 =C2=A0 =C2=A0 (org-dp-rewire '= ;src-block t t ;cont ins
<= span style=3D"white-space:pre"> =C2=A0 =C2=A0 =C2=A0t ;aff
= =C2=A0 =C2=A0 =C2=A0nil ;el= em
=C2=A0 =C2=A0 =C2=A0:= parameters ":results output"))

The point gets moved. Do you know why that happens?

John=

-----------------------------------
Professor John Kitchin=C2=A0=
Doherty Hall A207F
Department of Chemical Engineering
Carnegie Me= llon University
Pittsburgh, PA 15213
412-268-7803

On Sat, Mar 3, 2018 at 12:26 PM, Thorsten Jo= litz <tjolitz@gmail.com> wrote:
Thorsten Jolitz <tjolitz@gmai= l.com> writes:

PS
One more to show that one can not only easily modify a certain
org element, but that its just as easy to convert it to another type of
org element.

Use this (call M-x tj/obch)

#+BEGIN_SRC emacs-lisp
(defun tj/obch ()
=C2=A0 "docstring"
=C2=A0 (interactive)
=C2=A0 (org-dp-rewire 'example-block t t ;cont ins
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'(:captio= n (("val2" "key2") ("val2" "key2"))=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 :attr_xyz ("val1" "val2")) ;af= f
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0nil ;elem
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:language &qu= ot;common-lisp"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:switches = 9;(lambda (old elem) old )
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:parameters &= #39;tj/toggle-params
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:value '(= lambda (old elem)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0(let ((old1
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (string-remove-suffix "\= n" old)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(concat "(+ 3 " old1 " 17)\n&= quot;)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0:preserve-ind= ent '(lambda (old elem) old ) ) )
#+END_SRC

with point on this source block header

,----
| * test
|
| #+NAME: test1
| #+BEGIN_SRC emacs-lisp :tangle yes :results none
|=C2=A0 =C2=A0(+ 1 1)
| #+END_SRC
`----

to get this

,----
| #+NAME: test1
| #+CAPTION[key2]: val2
| #+CAPTION[key2]: val2
| #+ATTR_XYZ: val2
| #+ATTR_XYZ: val1
| #+BEGIN_EXAMPLE
| (+ 3 (+ 1 1) 17)
| #+END_EXAMPLE
`----




> John Kitchin <jkitchin@a= ndrew.cmu.edu> writes:
>
> Hallo,
>
>> This is a neat idea.
>
> This is quite a nice use/show case for org-dp too.
>
> I did not really try to solve the users feature request, just wanted t= o
> demonstrate how different a possible solution looks using declarative<= br> > programming, leaving all the low-level parsing and interpreting work t= o
> the org-element framework.
>
> 1. Example org-mode buffer
>
> ,----
> | * test
> |
> | #+NAME: test1
> | #+BEGIN_SRC emacs-lisp :tangle yes :results none
> |=C2=A0 =C2=A0(+ 1 1)
> | #+END_SRC
> |
> | #+NAME: test2
> | #+BEGIN_SRC picolisp :tangle no :results raw
> |=C2=A0 =C2=A0(+ 2 2)
> | #+END_SRC
> `----
>
> 2. Elisp to toggle the parameter values
>
> The org-dp part is this.
>
> Call the mapping cmd (M-x tj/obch-map) in the buffer (act on all
> src-blocks), or put point on a src-block header and call M-x tj/obch t= o
> just act on that scr-block.
>
> ,----
> | (defun tj/obch ()
> |=C2=A0 =C2=A0"docstring"
> |=C2=A0 =C2=A0(interactive)
> |=C2=A0 =C2=A0(org-dp-rewire 'src-block t t ;cont ins
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 t ;aff
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 nil ;elem
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :language '(lamb= da (old elem) old )
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :switches '(lamb= da (old elem) old )
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :parameters 'tj/= toggle-params
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :value '(lambda = (old elem) old )
> |=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :preserve-indent = 9;(lambda (old elem) old ) ) )
> |
> |
> | (defun tj/obch-map ()
> |=C2=A0 =C2=A0"docstring"
> |=C2=A0 =C2=A0(interactive)
> |=C2=A0 =C2=A0(org-dp-map '(tj/obch) "#\\+BEGIN_SRC")) > `----
>
> You can play around with the other args to org-dp-rewire (apart from > :parameters) to find out how easy you can change (or remove/add) other=
> parts of the src-block without any work on the textual representation.=
>
> E.g. try this:
>
> #+BEGIN_SRC emacs-lisp
> (defun tj/obch ()
>=C2=A0 =C2=A0"docstring"
>=C2=A0 =C2=A0(interactive)
>=C2=A0 =C2=A0(org-dp-rewire 'src-block t t ;cont ins
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 nil ;aff
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 nil ;elem
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :language "= ;common-lisp"
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :switches '= (lambda (old elem) old )
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :parameters = 9;tj/toggle-params
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :value '(la= mbda (old elem)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (let ((old1
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(string-remove-suffix "= ;\n" old)))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (concat "(+ 3 " old1 " 17)\n"))) >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :preserve-inden= t '(lambda (old elem) old ) ) )
> #+END_SRC
>
>
> to see this result in the example buffer after calling M-x tj/obch-map= :
>
> ,----
> | * test
> |
> | #+BEGIN_SRC common-lisp :tangle no :results raw
> |=C2=A0 =C2=A0(+ 3 (+ 1 1) 17)
> | #+END_SRC
> |
> | #+BEGIN_SRC common-lisp :tangle yes :results none
> |=C2=A0 =C2=A0(+ 3 (+ 2 2) 17)
> | #+END_SRC
> `----
>
> PS
> Here is the whole code.
> The logic in 'tj/toggle-params is not really of interest here. The=
> important thing is, that all of these options are possible:
>
> - simply assign a value
> - implement a lambda function in place (with two args)
> - implement a named function (with two args) and use its name
>
> ,----
> | :parameters ":tangle no"
> | :parameters '(lambda (old elem) (concat old " :results none= ") )
> | :parameters 'tj/toggle-params
> `----
>
> #+BEGIN_SRC emacs-lisp
> (defvar tj/change-p)
>
> ;; org-dp in action
> ;; wrap org-dp-rewire in utility cmd for readability
> (defun tj/obch ()
>=C2=A0 =C2=A0"docstring"
>=C2=A0 =C2=A0(interactive)
>=C2=A0 =C2=A0(org-dp-rewire 'src-block t t ;cont ins
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 t ;aff
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 nil ;elem
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :language '= (lambda (old elem) old )
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :switches '= (lambda (old elem) old )
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :parameters = 9;tj/toggle-params
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :value '(la= mbda (old elem) old )
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 :preserve-inden= t '(lambda (old elem) old ) ) )
>
>
> (defun tj/obch-map ()
>=C2=A0 =C2=A0"docstring"
>=C2=A0 =C2=A0(interactive)
>=C2=A0 =C2=A0(org-dp-map '(tj/obch) "#\\+BEGIN_SRC"))
>
> ;; helper functions for this use case, not really of interest
> ;; toggle src-block parameter values
> (defun tj/toggle-params (old elem)
>=C2=A0 =C2=A0"docstring"
>=C2=A0 =C2=A0(let* ((params-lst (split-string old)))
>=C2=A0 =C2=A0 =C2=A0(setq tj/change-p nil)
>=C2=A0 =C2=A0 =C2=A0(mapconcat 'tj/replace-vals params-lst " &= quot;)) )
>
> ;; helper functon to actually replace old with new values
> (defun tj/replace-vals (strg)
>=C2=A0 =C2=A0"docstring"
>=C2=A0 =C2=A0(let (res)
>=C2=A0 =C2=A0 =C2=A0(if tj/change-p
>=C2=A0 =C2=A0 =C2=A0 =C2=A0(progn
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cond
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((string-equal strg "yes")=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq res "no"))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((string-equal strg "no")<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq res "yes")) >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((string-equal strg "none"= )
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq res "raw")) >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((string-equal strg "raw")=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq res "none")) )=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq tj/change-p nil)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0res)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0(cond
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 ((string-equal strg ":tangle") >=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq tj/change-p t))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 ((string-equal strg ":results") >=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq tj/change-p t)))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0strg)))
> #+END_SRC
>
>
>> I sometimes want to switch to silent, or between
>> value and results. I don't know if you would consider the code= below an
>> improvement, but it seems to do what you want, and is shorter. It = has
>> less checking of things, and is more of a replace the header kind = of
>> approach.
>>
>> Personally, I think strings are the way to go here.
>>
>> #+BEGIN_SRC emacs-lisp :tangle yes :results none
>> (require 's)
>> (require 'dash)
>>
>> (defvar header-sequences '((emacs-lisp . (":tangle no :re= sults none" ;;
>> type 2 above
>> ":tangle yes :results none" ;; type 3 above
>> ":results type verbatim" ;; type 1 above
>> ))))
>>
>> (defun obch ()
>> (interactive)
>> (let* ((lang (car (org-babel-get-src-block-info t)))
>> (headers (cdr (assoc (intern-soft lang) header-sequences)))
>> header index)
>> (save-excursion
>> (org-babel-goto-src-block-head)
>> (re-search-forward lang)
>> (setq header (buffer-substring-no-properties (point)
>> (line-end-position))
>> index (-find-index (lambda (s) (string=3D (s-trim s) (s-trim heade= r)))
>> headers))
>> (delete-region (point) (line-end-position))
>> (insert " " (if index
>> (nth (mod (+ 1 index) (length headers)) headers)
>> (car headers))))))
>> #+END_SRC
>>
>> John
>>
>> -----------------------------------
>> Professor John Kitchin
>> Doherty Hall A207F
>> Department of Chemical Engineering
>> Carnegie Mellon University
>> Pittsburgh, PA 15213
>> 412-268-7803
>> @johnkitchin
>> http://kitchingroup.cheme.cmu.edu
>>
>> On Wed, Feb 28, 2018 at 2:59 AM, Akater <nuclearspace@gmail.com> wrote:
>>
>>=C2=A0 When I have a chance, I enjoy the following development work= flow:
>>=C2=A0 the
>>=C2=A0 code is written in org files and is tangled into conventiona= l source
>>=C2=A0 code files more or less regularly.
>>
>>=C2=A0 I find that source blocks mostly fall into three categories,=
>>=C2=A0 numbered
>>=C2=A0 here for further reference:
>>=C2=A0 - examples/test cases/desiderata, like
>>=C2=A0 `(my-implemented-or-desired-function x y)' (type 1)=
>>=C2=A0 - drafts, failed attempts at implementations and other snipp= ets
>>=C2=A0 better
>>=C2=A0 left as is, or as a warning (type 2)
>>=C2=A0 - working implementations, to be tangled (type 3)
>>
>>=C2=A0 Hence I end up using only a handful of header argument strin= gs. An
>>=C2=A0 example corresponding to this 3-cases setup is found below. = So it
>>=C2=A0 would
>>=C2=A0 be nice to have a function that cycles between those, much l= ike we
>>=C2=A0 can
>>=C2=A0 cycle through org TODO sequence now using a standard functio= n, and
>>=C2=A0 set
>>=C2=A0 up this sequence per Org file.
>>
>>=C2=A0 I'm fairly bad at Emacs Lisp, so I'm interested in f= eedback about my
>>=C2=A0 implementation of cycling function. It operates with strings= , mostly
>>=C2=A0 because I failed to make it work with lists of alists of hea= der
>>=C2=A0 arguments as ob-core.el suggests. On the other hand, given t= hat
>>=C2=A0 Emacs
>>=C2=A0 Lisp is more string-oriented than it is object-oriented, it = might
>>=C2=A0 not be
>>=C2=A0 a really bad idea.
>>
>>=C2=A0 So what do you think? How can this implementation be improve= d? (Sans
>>=C2=A0 using rotate and tracking position in a smarter way.) Does i= t make
>>=C2=A0 sense
>>=C2=A0 to include this feature in Org mode? Maybe I missed some exi= sting
>>=C2=A0 well-estabilished solutions? This is something akin to =E2= =80=9Cliterate
>>=C2=A0 programming=E2=80=9D; I'm not a fan of this idea---at le= ast the way it is
>>=C2=A0 usually presented---but it is somewhat popular a topic. I ha= ve some
>>=C2=A0 other feature in mind I'd love to see implemented in Org= -Babel:
>>=C2=A0 convenient export of src blocks of type 1 (see above) into u= nit
>>=C2=A0 tests
>>=C2=A0 (as test cases) and into documentation sources (as examples)= but
>>=C2=A0 this
>>=C2=A0 one is heavily target-language dependent and probably deserv= es its
>>=C2=A0 own
>>=C2=A0 thread.
>>
>>=C2=A0 #+begin_src emacs-lisp
>>=C2=A0 (cl-defun next-maybe-cycled (elem list &key (test #'= equal))
>>=C2=A0 "Returns the element in `list' next to the first `e= lem' found. If
>>=C2=A0 `elem' is found at `list''s very tail, returns `= list''s car.
>>=C2=A0 `next-maybe-cycled' provides no way to distinguish betwe= en \"found
>>=C2=A0 nil\" and \"found nothing\"."
>>=C2=A0 (let ((sublist (cl-member elem list :test test)))
>>=C2=A0 (and sublist
>>=C2=A0 (if (cdr sublist)
>>=C2=A0 (cadr sublist)
>>=C2=A0 (car list)))))
>>
>>=C2=A0 (defun shrink-whitespace (string)
>>=C2=A0 "Transforms all whitespace instances into single spaces= . Trims
>>=C2=A0 whitespace at beginning and end. No argument type checking.&= quot;
>>=C2=A0 (cl-reduce (lambda (string rule)
>>=C2=A0 (replace-regexp-in-string (car rule) (cdr rule) string))
>>=C2=A0 '(("[[:blank:]]+" . " ") ("^[[:= blank:]]*" . "") ("[[:blank:]]*$" .
>>=C2=A0 ""))
>>=C2=A0 :initial-value string))
>>
>>=C2=A0 (defun string-equal-modulo-whitespace (x y)
>>=C2=A0 (string-equal (shrink-whitespace x) (shrink-whitespace y)))<= br> >>
>>=C2=A0 (defun org-babel-cycle-src-block-header-string (header-= strings)
>>=C2=A0 "Cycle through given `header-strings' if currently = in Org Babel
>>=C2=A0 source code block. If current src-block header is not found = in
>>=C2=A0 `header-strings', switch header to the car of `header-st= rings'.
>>
>>=C2=A0 `header-strings' must be a non-empty list of strings. Al= l whitespace
>>=C2=A0 in them is shrinked.
>>
>>=C2=A0 If UNDO-ed, cursor position is not guaranteed to be preserve= d."
>>=C2=A0 (interactive)
>>=C2=A0 (cond
>>=C2=A0 ((not (and header-strings (listp header-strings)))
>>=C2=A0 (error "No Org Babel header strings list found to cycle= through. %S
>>=C2=A0 found intstead." header-strings))
>>=C2=A0 ((not (every #'stringp header-strings))
>>=C2=A0 (error "Malformed list of Org Babel header strings: not= all elements
>>=C2=A0 are strings in %S." header-strings))
>>=C2=A0 (t
>>=C2=A0 (let ((initial-position (point)))
>>=C2=A0 (org-babel-goto-src-block-head)
>>=C2=A0 ;; here we rely on `org-babel-goto-src-block-head'<= br> >>=C2=A0 ;; signalling an error if not in source code block
>>=C2=A0 (forward-char (length "#+BEGIN_SRC"))
>>=C2=A0 (let* ((fallback-position (point))
>>=C2=A0 (we-were-before-replacement-zone (<=3D initial-posit= ion
>>=C2=A0 fallback-position)))
>>=C2=A0 (let ((default-position-to-return-to initial-position)<= br> >>=C2=A0 (old-header-string (delete-and-extract-region (point)
>>=C2=A0 (line-end-position))))
>>=C2=A0 (unless we-were-before-replacement-zone
>>=C2=A0 (incf default-position-to-return-to (- (length old-header-st= ring))))
>>=C2=A0 (let ((new-header-string
>>=C2=A0 (concatenate 'string
>>=C2=A0 " "
>>=C2=A0 (shrink-whitespace
>>=C2=A0 (or (next-maybe-cycled old-header-string
>>=C2=A0 header-strings
>>=C2=A0 :test #'string-equal-modulo-whitespace)
>>=C2=A0 (car header-strings))))))
>>=C2=A0 (insert new-header-string)
>>=C2=A0 (unless we-were-before-replacement-zone
>>=C2=A0 (incf default-position-to-return-to (length new-header-strin= g)))
>>=C2=A0 (goto-char (if (<=3D fallback-position
>>=C2=A0 default-position-to-return-to
>>=C2=A0 (+ fallback-position (length new-header-string)))
>>=C2=A0 fallback-position
>>=C2=A0 default-position-to-return-to)))))))))
>>
>>=C2=A0 ;; example for mailing list
>>=C2=A0 ;; Common Lisp assumed!
>>=C2=A0 (defun akater/org-babel-cycle-header nil
>>=C2=A0 (interactive)
>>=C2=A0 (org-babel-cycle-src-block-header-string
>>=C2=A0 '("lisp :tangle no :results none" ;; type 2 ab= ove
>>=C2=A0 "lisp :tangle yes :results none" ;; type 3 above >>=C2=A0 "lisp :results type verbatim" ;; type 1 above
>>=C2=A0 )))
>>=C2=A0 #+end_src
>>
>>=C2=A0 Ideally, I envision something along these lines (some specif= ic
>>=C2=A0 choices
>>=C2=A0 below don't really make sense):
>>=C2=A0 #+begin_src emacs-lisp
>>=C2=A0 (defcustom org-babel-standard-header-sequences-alist >>=C2=A0 '((development-setup-1
>>=C2=A0 (lisp
>>=C2=A0 (((:tangle . "no")
>>=C2=A0 (:results . "none"))
>>=C2=A0 ((:tangle . "yes")
>>=C2=A0 (:results . "none"))
>>=C2=A0 ((:results . "type verbatim"))))
>>=C2=A0 (python
>>=C2=A0 (((:tangle . "no")
>>=C2=A0 (:results . "none"))
>>=C2=A0 ((:tangle . "yes")
>>=C2=A0 (:results . "none"))
>>=C2=A0 ((:results . "type output"))))
>>=C2=A0 )
>>=C2=A0 (development-setup-2
>>=C2=A0 (C
>>=C2=A0 (((:tangle . "no")
>>=C2=A0 (:results . "none"))
>>=C2=A0 ((:tangle . "yes")
>>=C2=A0 (:results . "raw"))))
>>=C2=A0 (julia
>>=C2=A0 (((:tangle . "no")
>>=C2=A0 (:results . "none"))
>>=C2=A0 ((:tangle . "yes")
>>=C2=A0 (:results . "none")))))))
>>=C2=A0 #+end_src
>>
>>

--
cheers,
Thorsten



--089e082f38c4abeee905669e4cad--