Hi, First, Thierry, I think this patch fixes the second misbehavior you observed.
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)) Cheers, Rasmus -- 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 customized" :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)) (boolean))))) @@ -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." (forward-line))))))) (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 +context. + +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 +`org-element-multiple-keywords')." + (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 -- 2.1.3