Hi, Thanks for the comments.
This email is long (sorry); fortunately there are many blank lines. . . Thierry Banel <tbanelweb...@free.fr> writes: > If not, maybe it would be better to keep the oriGiNaL cASe. Yeah, fixed. Nicolas Goaziou <m...@nicolasgoaziou.fr> writes: > Rasmus <ras...@gmx.us> writes: > >>> 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. > > M-RET, is, first and foremost, an important keybinding for editing the > /structure/ of the document. The behaviour you want to add has nothing > to do with structure. I see it differently. I see M-RET as a function that "magically" adds more of what is adjacent to point. I—obviously—think what I propose is better than what we have now. Let's go through the current functionality. * Example 1: #+LATEX_HEADER: foo Click M-RET anywhere above (line-beginning-position) and you get something like #+LATEX * _HEADER: foo This is nonsense. Click M-RET at (line-beginning-position) and you get * #+LATEX_HEADER: foo This is nonsense. * Example 2 - s #+LATEX_HEADER: foo % no space between ^ and #. Same as example 2. * Next case - s #+LATEX_HEADER: foo % space between ^ and # M-RET at a position greater than (line-beginning-position) yields something like - s #+LATEX - _HEADER: tes This is nonsense. M-RET at (line-beginning-position) will yield - s - | ← that's point #+LATEX_HEADER: foo % space between ^ and # Thus far this is the only sensible result that we'd loose with the patch. If this is a great loss (rather than a bug in the current implementation) this can be dealt with, though it adds complexity to the meaning of M-RET (since it's a function of the previous element rather than the adjacent one). * Example 4 - s #+LATEX_HEADER: foo % three spaces This works like example 1. > As a consequence, I'm not sure it should go with M-RET, and if it does, > I'm pretty sure it should not override the main purpose of the binding. > Inserting headlines, and possibly items, is much more important than > duplicating keywords. IMO the examples above show that M-RET fails at doing this in a sensible manner is all but one case above. The case where it does not fail requires (i) that the keyword is not at the beginning of the line and (ii) that the use has point before the keyword. I don't care strongly about this "feature"—It's just check that point is not at bol in `org-meta-return'. In fact I would be happy to go further. One also get nonsense result doing M-RET on #+begin_src lines and probably elsewhere. >> Also, `org-insert-keyword' is not really using org-element anymore. > > It should since you make it interactive and can, therefore, be called on > its own. I moved the check to a separate function, `org-looking-at-repeatable-keyword-p'. There are now the following issues: 1. it's called twice: once in org-meta-return and once in org-insert-keyword. I'm not sure if it's possible to emit a signal to avoid the second check somehow... Perhaps the performance-loss is such that we should not worry about it. 2. The name is terrible. I'm also not sure if this function should reside in org.el. Same for the regexp. Thoughts? > Some comments follow: Thanks for these! >> + (indention >> + (buffer-substring >> + (line-beginning-position) >> + (save-excursion >> + (beginning-of-line) >> + (skip-chars-forward " \t") >> + (point)))) > > Another option: > > (ind (org-get-indentation)) Cool. I really need to internalize to look for org-prefixed functions! >> + (keyword-re "#\\+\\(.+?\\):") >> + (key (save-excursion (beginning-of-line) >> + (skip-chars-forward " \t") >> + (looking-at keyword-re) >> + (upcase (org-match-string-no-properties 1)))) > > As discussed above, this is too fragile. You need to duplicate the > checks done in `org-meta-return' or refactor the code. Yeah, I see your point. Casual testing suggest it's more solid now albeit there's now the double check as outlined above. >> + (end-of-keyword (save-excursion >> + (beginning-of-line) >> + (re-search-forward keyword-re (line-end-position) t) >> + (point)))) > > (end-of-keyword (save-excursion (beginning-of-line) (search-forward ":")) > [...] > I think end-of-keyword should be bound after KEY is checked to avoid > errors. Since there's now a check before entering the function I guess this should be safe. Still I added extra checks, that I'm pretty sure are unnecessary. I'd be happy to remove these. —Rasmus -- Don't panic!!!
>From 7443986c8d10efc7ee3216c3dbac6a5ace8a4468 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-keyword-regexp): Regexp to detect keyword. (org-looking-at-repeatable-keyword-p): New function. (org-insert-keyword): New function. (org-meta-return): May call `org-insert-keyword'. (org-M-RET-may-split-line): Add keyword. --- lisp/org.el | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 11 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 6ab13f4..6e75db4 100755 --- a/lisp/org.el +++ b/lisp/org.el @@ -440,6 +440,12 @@ Matched keyword is in group 1.") (concat "\\<" org-closed-string " *\\[\\([^]]+\\)\\]") "Matches the CLOSED keyword together with a time stamp.") +(defconst org-keyword-regexp + "^[ \t]*#\\+\\(.+?\\):" + "Matches keywords such as #+LATEX_HEADER: and #+CAPTION:. + +See also `org-looking-at-repeatable-keyword-p'.") + (defconst org-keyword-time-regexp (concat "\\<" (regexp-opt @@ -1601,6 +1607,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 +1621,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 +7733,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 +21299,90 @@ number of stars to add." (forward-line))))))) (unless toggled (message "Cannot toggle heading from here")))) +(defun org-looking-at-repeatable-keyword-p () + "Return non-nil if point is at repeatable keyword. + +Repeatable keyword are either keywords that are not members of +`org-element-affiliated-keywords' or affiliated keywords that are +members of `org-element-multiple-keywords'." + (let ((element (org-element-at-point)) + (type (org-element-type element))) + (or (eq type 'keyword) + (< (point) (org-element-property :post-affiliated element))) + (let ((key (save-excursion + (beginning-of-line) + (and (looking-at org-keyword-regexp) + (org-match-string-no-properties 1))))) + (and key + (or (not (member-ignore-case + key org-element-affiliated-keywords)) + (member-ignore-case + key org-element-multiple-keywords)))))) + +(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") + (when (org-looking-at-repeatable-keyword-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 (org-get-indentation)) + (key (save-excursion (beginning-of-line) + (and (looking-at org-keyword-regexp) + (org-string-nw-p (org-match-string-no-properties 1))))) + (end-of-keyword (and key + (save-excursion + (beginning-of-line) + (search-forward ":" (line-end-position) t) + (point))))) + (when key + (cond (point-at-bol-p + ;; Point is before keyword. + + ;; TODO: Perhaps it should call `org-insert-heading' + ;; when point-at-bol-p. If so this check should be in + ;; `org-meta-return'. + + ;; TODO: it would be nice to have the insert \n after + ;; the cond, but the save-excursion would somehow need + ;; to be applied... + (save-excursion + (beginning-of-line) + (insert "\n"))) + ((or (not may-split) + (< (point) end-of-keyword)) + (end-of-line) + (insert "\n")) + (t (insert "\n"))) + (org-indent-line-to indention) + (insert (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 +21391,14 @@ 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)) + ((org-looking-at-repeatable-keyword-p) + (call-interactively 'org-insert-keyword)) + (t (call-interactively 'org-insert-heading)))))) ;;; Menu entries -- 2.1.3