I guess this is a feature of deleting a region with the point in it. This code, for example, does not preserve point. #+BEGIN_SRC emacs-lisp "<>" (save-excursion (let* ((p1 (point)) (p2 (re-search-backward (concat "<" ">"))) (content (buffer-substring-no-properties p1 p2))) (delete-region p1 p2) (insert content))) #+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 Sun, Mar 4, 2018 at 4:21 PM, Thorsten Jolitz wrote: > John Kitchin writes: > > > 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? > > Hmm ... org-dp-rewire is mostly fidling around with lists, but in the > end it acts conditionally on the 'replace' parameter: > > ,---- > | (if (and (marker-position beg) > | (marker-position end)) > | (cl-case replace > | (append (save-excursion (goto-char end) (insert strg))) > | (prepend (goto-char beg) (insert strg)) > | (t (if (not replace) > | strg > | (delete-region beg end) > | (goto-char end) > | (set-marker beg nil) > | (set-marker paff nil) > | (set-marker end nil) > | (save-excursion (insert strg))))) > | (if replace (insert strg) strg)))) > `---- > > append or prepend result, return it as string, or replace the rewired > element. > I guess the is a save-excursion missing here ... > > > 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 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 :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= (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 “literate > > >> programming”; I'm not a fan of this idea---at least the way it 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 (<= 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 (<= 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 > > > > > > -- > cheers, > Thorsten > > >