emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Two potentially useful functions for org-element
@ 2014-08-06 23:01 Thorsten Jolitz
  2014-08-07  8:59 ` Thorsten Jolitz
  2014-08-08  8:03 ` Nicolas Goaziou
  0 siblings, 2 replies; 4+ messages in thread
From: Thorsten Jolitz @ 2014-08-06 23:01 UTC (permalink / raw)
  To: emacs-orgmode


Hi List, 

now that I understand the 'org-element API' a bit better, I think that
the following two functions can be very useful for creating and
modifying Org elements without the usual point movements, regexp
searches and string operations in a buffer:

#+begin_src emacs-lisp
;; might become `org-element-create'
(defun* tj/create-element (&optional insert-p &rest args &key (type 'headline) &allow-other-keys)
  "Create Org element, maybe insert at point."
  (let ((strg (org-element-interpret-data
	       (list type args))))
    (if insert-p (insert strg) strg)))
#+end_src

#+results:
: tj/create-element


#+begin_src emacs-lisp
;; might become `org-element-rewire'
(defun* tj/rewire-element (&optional replace &rest args &key type &allow-other-keys)
  "Rewire element at point, maybe replace it."
  (let* ((elem (org-element-at-point))
	 (plist (cadr elem))
	 (beg (org-element-property :begin elem))
	 (end (org-element-property :end elem))
	 strg)
    (while args
	  (setq plist (plist-put plist (pop args) (pop args))))
    (setq strg (org-element-interpret-data
		(list
		 (or type (org-element-type elem))
		 plist)))
    (case replace
      (append (save-excursion (goto-char end) (insert strg)))
      (prepend (goto-char beg) (insert strg))
      (t (if replace
	     (let ((marker (save-excursion
			     (goto-char end) (point-marker))))
	       (delete-region beg end)
	       (goto-char marker)
	       (save-excursion (insert strg)))
	   strg)))))
#+end_src

#+results:
: tj/rewire-element

Here are a few usage examples:

#+begin_src emacs-lisp
  (tj/create-element nil
                     :type 'src-block
                     :language "emacs-lisp"
                     :value "(+ 2 2)\n"
                     :parameters ":results raw"
                     :name "myblock"
                     :header '(":var x=5"))
#+end_src

#+results:
: #+NAME: myblock
: #+HEADER: :var x=5
: #+BEGIN_SRC emacs-lisp :results raw
:   (+ 2 2)
: #+END_SRC

#+begin_src emacs-lisp :wrap org
  (tj/create-element nil
                     :type 'headline
		     :level 2
                     :todo-keyword "DONE"
                     :priority 66
                     :title "Hello World"
                     :tags '("tag1" "tag2"))
#+end_src

#+results:
#+BEGIN_org
,** DONE [#B] Hello World :tag1:tag2:
#+END_org

Now eval next src-block


#+begin_src emacs-lisp
  (defun test-fun ()
    (tj/rewire-element 'append
                       :parameters ":results table :exports both"
                       :name (format "random-block-%d" (1+ (random 11)))
                       :header '(":var x=5")
                       :value (format "%s\n%s\n" '(+ 2 2) '(* 3 x))))
#+end_src

#+results:
: test-fun

and then, with point at beginning of following src-block, eval 'M-: (test-fun)'

#+BEGIN_SRC emacs-lisp :results raw
  (+ 2 2)
#+END_SRC


#+NAME: random-block-6
#+HEADER: :var x=5
#+BEGIN_SRC emacs-lisp :results table :exports both
  (+ 2 2)
  (* 3 x)
#+END_SRC


-- 
cheers,
Thorsten

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

* Re: Two potentially useful functions for org-element
  2014-08-06 23:01 Two potentially useful functions for org-element Thorsten Jolitz
@ 2014-08-07  8:59 ` Thorsten Jolitz
  2014-08-08  8:03 ` Nicolas Goaziou
  1 sibling, 0 replies; 4+ messages in thread
From: Thorsten Jolitz @ 2014-08-07  8:59 UTC (permalink / raw)
  To: emacs-orgmode

Thorsten Jolitz <tjolitz@gmail.com> writes:

Hi List, 

> now that I understand the 'org-element API' a bit better, I think that
> the following two functions can be very useful for creating and
> modifying Org elements without the usual point movements, regexp
> searches and string operations in a buffer:
>
> #+begin_src emacs-lisp
> ;; might become `org-element-create'
> (defun* tj/create-element (&optional insert-p &rest args &key (type 'headline) &allow-other-keys)
>   "Create Org element, maybe insert at point."
>   (let ((strg (org-element-interpret-data
> 	       (list type args))))
>     (if insert-p (insert strg) strg)))
> #+end_src

I made the second 'rewire element' function smarter so that it can now
reuse the old value when setting a new value for a property of the
'rewired' element:

#+begin_src emacs-lisp
  ;; might become `org-element-rewire'
  (defun* tj/rewire-element (&optional replace &rest args &key type &allow-other-keys)
    "Rewire element at point, maybe replace it.
  The former value of an element property can be reused in the
  creation of a new value by giving a `lambda' expession with one
  function argument instead of a value to a key. That argument will
  then be replaced by the property's former value when applying the
  function."
    (let* ((elem (org-element-at-point))
           (plist (cadr elem))
           (beg (org-element-property :begin elem))
           (end (org-element-property :end elem))
           strg)
      (while args
        (let* ((key (pop args))
               (val-or-fun (pop args))
               (old-val (org-element-property key elem))
               (new-val
                (if (functionp val-or-fun)
                    (apply val-or-fun (list old-val))
                  val-or-fun)))
            (setq plist (plist-put plist key new-val))))
      (setq strg (org-element-interpret-data
                  (list (or type (org-element-type elem)) plist)))
      (case replace
        (append (save-excursion (goto-char end) (insert strg)))
        (prepend (goto-char beg) (insert strg))
        (t (if replace
               (let ((marker (save-excursion
                               (goto-char end) (point-marker))))
                 (delete-region beg end)
                 (goto-char marker)
                 (set-marker marker nil)
                 (save-excursion (insert strg)))
             strg)))))
#+end_src

#+results:
: tj/rewire-element

Here a few examples, all of them assuming point is at beginning of
this src-block if not stated otherwise:

#+begin_src emacs-lisp
(+ 2 2)
#+end_src

1. do M-: [content-of-next-src-block]

#+begin_src emacs-lisp
  (tj/rewire-element 'append
                     :name (format "rewired-%d" (1+ (random 10))))
#+end_src

#+NAME: rewired-7
#+BEGIN_SRC emacs-lisp
  (+ 2 2)
#+END_SRC

2. do M-: [content-of-next-src-block]

#+begin_src emacs-lisp
  (tj/rewire-element 'append
                     :name (lambda (_old_)
                             (if _old_
                                 (format "rewired-%d"
                                         (* (string-to-number
                                             (car
                                              (last
                                               (split-string _old_ "-" t))))
                                            (1+ (random 10))))
                               (format "rewired-%d" (1+ (random 10)))))
                     :language "picolisp")
#+end_src

gives 

#+NAME: rewired-2
#+BEGIN_SRC picolisp
  (+ 2 2)
#+END_SRC

when called on the original src-block, but 

#+NAME: rewired-63
#+BEGIN_SRC picolisp
    (+ 2 2)
#+END_SRC

when called on the result of usage example 1 (with name rewired-7).

3. do M-: [content-of-next-src-block]

#+begin_src emacs-lisp
  (tj/rewire-element 'append
                     :value (lambda (_old_)
                              (concat
                               "(message \"%d\" "
                               (car
                                (split-string
                                 _old_ "\n" t)) ")\n"))
                     :parameters ":results raw")
#+end_src

gives

#+BEGIN_SRC emacs-lisp :results raw
  (message "%d" (+ 2 2))
#+END_SRC

-- 
cheers,
Thorsten

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

* Re: Two potentially useful functions for org-element
  2014-08-06 23:01 Two potentially useful functions for org-element Thorsten Jolitz
  2014-08-07  8:59 ` Thorsten Jolitz
@ 2014-08-08  8:03 ` Nicolas Goaziou
  2014-08-08  8:27   ` Thorsten Jolitz
  1 sibling, 1 reply; 4+ messages in thread
From: Nicolas Goaziou @ 2014-08-08  8:03 UTC (permalink / raw)
  To: Thorsten Jolitz; +Cc: emacs-orgmode

Hello,

Thorsten Jolitz <tjolitz@gmail.com> writes:

> now that I understand the 'org-element API' a bit better, I think that
> the following two functions can be very useful for creating and
> modifying Org elements without the usual point movements, regexp
> searches and string operations in a buffer:

Element isn't really meant to provide tools to modify the buffer. It is
only a parser, i.e. buffer to parse tree transformation.

The reciprocal, i.e., modifying a parse tree in order to alter the
buffer may belong to another library. IIRC, this is the goal of
"org-sync" (from GSOC 2012). You may want to look into it.


Regards,

-- 
Nicolas Goaziou

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

* Re: Two potentially useful functions for org-element
  2014-08-08  8:03 ` Nicolas Goaziou
@ 2014-08-08  8:27   ` Thorsten Jolitz
  0 siblings, 0 replies; 4+ messages in thread
From: Thorsten Jolitz @ 2014-08-08  8:27 UTC (permalink / raw)
  To: emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Hello,
>
> Thorsten Jolitz <tjolitz@gmail.com> writes:
>
>> now that I understand the 'org-element API' a bit better, I think that
>> the following two functions can be very useful for creating and
>> modifying Org elements without the usual point movements, regexp
>> searches and string operations in a buffer:
>
> Element isn't really meant to provide tools to modify the buffer. It is
> only a parser, i.e. buffer to parse tree transformation.
>
> The reciprocal, i.e., modifying a parse tree in order to alter the
> buffer may belong to another library. IIRC, this is the goal of
> "org-sync" (from GSOC 2012). You may want to look into it.

Sorry, did not read this before writing my other recent post ...

I will have a look at org-sync, but even if Element isn't really meant
to provide tools to modify the buffer, it seems to be tremendously
useful in doing so? The most limiting aspect I found is the missing
access to an elements content (see my parallel post wrt to this topic). 

Otherwise 'rewiring' an elements internals looks like a huge
productivity booster compared to the usual buffer operations on the
textual representation. As long as the interpreter works as expected,
and it does!

-- 
cheers,
Thorsten

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

end of thread, other threads:[~2014-08-08  8:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-06 23:01 Two potentially useful functions for org-element Thorsten Jolitz
2014-08-07  8:59 ` Thorsten Jolitz
2014-08-08  8:03 ` Nicolas Goaziou
2014-08-08  8:27   ` Thorsten Jolitz

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