First, Thierry, I think this patch fixes the second misbehavior you

Nicolas Goaziou <m...@nicolasgoaziou.fr> writes:

I looked through your comments and as always they made the patch much
better!  Thanks!

> Moreover, it can get in the way of expected M-RET behaviour, as in the
> following example
>   - item
>   | #+caption: test
>     untenrsiu

I don't know if I should do something about this case.  I guess it would
be possible, but I find it awkward when behavior $BUTTON depends not
only on not only the adjacent element, but also the previous element.

If it's important, I guess it should be toggled explicitly on by a
custom variable.

>   (point-at-bol-p (save-excursion (skip-chars-backward " \t") (bolp)))
> See last paragraph in `looking-back' docstring.

Thanks, that's nice.

> Also, you're not supposed to use `org-element--affiliated-re', as
> suggested by the double hyphen. If you want to tell when point is at an
> affiliated keyword, use
>   (< (point) (org-element-property :post-affiliated element))

That's a great tip in its own right, but actually I used
`org-element--affiliated-re' for determining if point was "in"/"on" the
keyword, as here:

       #+CAPT|ION: foo

Anyway, I changed it to fixed regexp.  Presently, it's hardcoded.
Should I introduce a new defvar or just live with the hardcodedness?

> where ELEMENT is returned by `org-element-at-point'. You can then
> extract its name with, e.g.,
>   (save-excursion 
>    (beginning-of-line)
>    (looking-at "#\\+\\(.+?\\):")
>    (upcase (org-match-string-no-properties 1)))

In the current patch I run this code twice, once in `org-meta-return',
once in `org-insert-keyword' (basically twice).  I would probably be
possible to pass the keyword as an argument, but I'm not sure it's worth
it.  Also, `org-insert-keyword' is not really using org-element anymore.

>> +     (elm (org-element-at-point))
>> +     (key (and (eq 'keyword (org-element-type elm))
>> +               (org-element-property :key elm))))
>> +    (when key
> KEY is nil when at an affiliated keyword. So this function is a no-op
> on #+CAPTION: and alike.  Try it on a real caption, e.g.,
>   #+CAPTION: caption
>   Paragraph

Good call.  I detect this case with
(org-element-property :post-affiliated element) now.  It seems to work
in the variation of this I could come up with.  Quick testing suggest
that affiliated keywords are always on the top of an (greater) element.

>> +      (when point-at-bol-p (open-line 1)
>> +        ;; Open-line makes sometimes ruins indention of the
>> +        ;; previous line.
>> +        (save-excursion (forward-line 1)
>> +                        (org-indent-line)))
> Don't use `open-line' at all. Insert "\n" where appropriate. Also avoid
> using `org-indent-line' since you can already know what the expected
> indentation is (i.e., by storing it earlier).

Thanks.  Actually, I think I saw `open-line' in `org-insert-headline`
and that's why I used it.  Perhaps that's another patch.
>> +           ((and (eq type 'keyword)
>> +                 ;; Keyword such as LATEX, ATTR_LATEX, CAPTION, and HEADER,
>> +                 ;; LATEX_HEADER, LATEX etc. can occur multiple times.
>> +                 (let ((key (org-element-property :key element)))
>> +                   (if (member key org-element-affiliated-keywords)
>> +                       (member key org-element-multiple-keywords)
>> +                     t)))
> KEY cannot belong to `org-element-affiliated-keywords'.  See above.

It test that *if* it's a member of `org-element-affiliated-keywords'
then it should also be a member of `org-element-multiple-keywords'.
Anyway, your test is nicer:

> Also,
>   (or (not (member key org-element-affiliated-keywords))
>       (member key org-element-multiple-keywords))


Summon the Mothership!
>From 2e70cf7c7df61eebcc10e48077c5212d9015900e Mon Sep 17 00:00:00 2001
From: rasmus <ras...@gmx.us>
Date: Wed, 19 Nov 2014 15:39:19 +0100
Subject: [PATCH] org.el: Add keyword-support to M-RET

* org.el (org-insert-keyword): New function.
(org-meta-return): May call `org-insert-keyword'.
(org-M-RET-may-split-line): Add keyword.
 lisp/org.el | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 80 insertions(+), 11 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 6ab13f4..3405ab4 100755
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -1601,6 +1601,7 @@ contexts.  Valid contexts are:
 headline  when creating a new headline
 item      when creating a new item
 table     in a table field
+keyword   when creating a new keyword
 default   the value to be used for all contexts not explicitly
   :group 'org-structure
@@ -1614,6 +1615,7 @@ default   the value to be used for all contexts not explicitly
 			   (const headline)
 			   (const item)
 			   (const table)
+			   (const keyword)
 			   (const default))
@@ -7725,8 +7727,8 @@ split the line and create a new headline with the text in the
 current line after point \(see `org-M-RET-may-split-line' on how
 to modify this behavior).
-If point is at the beginning of a normal line, turn this line
-into a heading.
+If point is at the beginning of a normal line, excluding some
+keywords, turn this line into a heading.
 When INVISIBLE-OK is set, stop at invisible headlines when going
 back.  This is important for non-interactive uses of the
@@ -21291,10 +21293,65 @@ number of stars to add."
     (unless toggled (message "Cannot toggle heading from here"))))
+(defun org-insert-keyword (&optional arg)
+  "Insert a new keyword-line, such as #+CAPTION or #+LATEX_HEADER.
+If point is between the beginning of the line and the beginning
+of the keyword, as denoted by \"#\", a keyword-line is inserted
+above the current one.  If the point is within the keyword, a new
+keyword-line is inserted below.
+If point is in the middle of a keyword-line, after the keyword
+itself, split the line depending on the value of
+`org-M-RET-may-split-line'.  See the docstring of this variable
+for further details.
+Currently arg is ignored and the keyword is determined from the
+The function is used by `org-meta-return'.  Note, affiliated
+keywords that are not allowed to appear multiple times are
+ignored by `org-meta-return' (see
+`org-element-affiliated-keywords' and
+  (interactive "P")
+  (let* ((may-split (org-get-alist-option
+		     org-M-RET-may-split-line 'keyword))
+	 (point-at-bol-p
+	  (save-excursion (skip-chars-backward " \t") (bolp)))
+	 (indention
+	  (buffer-substring
+	   (line-beginning-position)
+	   (save-excursion
+	     (beginning-of-line)
+	     (skip-chars-forward " \t")
+	     (point))))
+	 (keyword-re "#\\+\\(.+?\\):")
+	 (key (save-excursion (beginning-of-line)
+			      (skip-chars-forward " \t")
+			      (looking-at keyword-re)
+			      (upcase (org-match-string-no-properties 1))))
+	 (end-of-keyword (save-excursion
+			   (beginning-of-line)
+			   (re-search-forward keyword-re (line-end-position) t)
+			   (point))))
+    (when key
+      (when point-at-bol-p
+	(save-excursion
+	  (beginning-of-line)
+	  (insert "\n")))
+      (unless may-split (end-of-line))
+      (unless point-at-bol-p
+	(when (< (point) end-of-keyword) (end-of-line))
+	(insert "\n"))
+      (insert (concat indention (format "#+%s: " key)))
+      (delete-region (point) (save-excursion (skip-chars-forward " \t") (point))))))
 (defun org-meta-return (&optional arg)
-  "Insert a new heading or wrap a region in a table.
-Calls `org-insert-heading' or `org-table-wrap-region', depending
-on context.  See the individual commands for more information."
+  "Insert a new heading, a new keyword or wrap a region in a table.
+Calls `org-insert-heading', `org-insert-keyword' or
+`org-table-wrap-region', depending on context.  See the
+individual commands for more information."
   (interactive "P")
   (org-check-before-invisible-edit 'insert)
   (or (run-hook-with-args-until-success 'org-metareturn-hook)
@@ -21303,12 +21360,24 @@ on context.  See the individual commands for more information."
         (when (eq type 'table-row)
           (setq element (org-element-property :parent element))
           (setq type 'table))
-        (if (and (eq type 'table)
-                 (eq (org-element-property :type element) 'org)
-                 (>= (point) (org-element-property :contents-begin element))
-                 (< (point) (org-element-property :contents-end element)))
-            (call-interactively 'org-table-wrap-region)
-          (call-interactively 'org-insert-heading)))))
+        (cond  ((and (eq type 'table)
+		      (eq (org-element-property :type element) 'org)
+		      (>= (point) (org-element-property :contents-begin element))
+		      (< (point) (org-element-property :contents-end element)))
+		(call-interactively 'org-table-wrap-region))
+	       ((and
+		 (or (eq type 'keyword)
+		     (<  (point) (org-element-property :post-affiliated element)))
+		 (let ((key (save-excursion
+			      (beginning-of-line)
+			      (skip-chars-forward " \t")
+			      (and (looking-at "#\\+\\(.+?\\):")
+				   (upcase (org-match-string-no-properties 1))))))
+		   (and key
+			(or (not (member key org-element-affiliated-keywords))
+			    (member key org-element-multiple-keywords)))))
+		(call-interactively 'org-insert-keyword))
+	       (t (call-interactively 'org-insert-heading))))))
 ;;; Menu entries

Reply via email to