Re: [Pre-PATCH v2] Add the capability to specify lexical scope in tangled files (was: Add new :lexical header argument)
Hi Ihor On August 23, 2023 12:44:32 PM GMT+01:00, Ihor Radchenko wrote: >Ihor Radchenko writes: > >> What about generalizing the idea and providing a way to set Emacs >> buffer-local variables in the tangled files? >> >> Can be something like: >> >> #+begin_src elisp :file-locals (lexical-binding t eval (line-number-mode)) > >Over one month have passed since the last message in this thread. > >Evgenii, are you still interested to continue working on this? > I am busy for the next month and even after that generalizing the idea would take too much effort and time, since I'm not an advanced programmer. So probably the answer is no.
Re: [FR] Add an option to use ID links during tangling
Ihor Radchenko writes: > Evgenii Klimov writes: > >> I see in the comment there the reason for that, but still would prefer >> to use unique IDs in tangled files: the probability to overwrite wrong >> source block under nonunique header overweights a side-effect of >> creating new ID in Org file during tangling. > > Did you actually encounter such situation? > `org-babel-detangle' is far from ideal in general. > For example, detangling noweb references is pretty much guaranteed to > create mess. Yes, I did. I keep my whole emacs configuration in an Org file and tangle it after adjustments at Emacs startup (~org-babel-load-file~). Recently I decided to split the tangled file and learned about detangling. And I have a lot of similar headers since my Org file looks like this: #+begin_example * package 1 ** basic ** custom functions ** custom bindings * package 2 ** basic ** custom functions ** custom bindings #+end_example >> Can we do something with this? Add another option or provide an even >> eager value in =org-id-link-to-org-use-id=. > > I do not like the idea of creating side effects in the original Org > document during tangling. > We can, however, use (org-id-link-to-org-use-id 'use-existing) to use > the already present IDs. Understandable, with (org-id-link-to-org-use-id 'use-existing) I would at least be able to manually add them where needed. > Ideally, we should improve the detangling to understand the order of > blocks better instead of searching the containing heading independently. Maybe recent feature suggestion [1] will be of use here. [1] https://list.orgmode.org/118435e8-0b20-46fd-af6a-88de8e19f...@app.fastmail.com
[FR] Add an option to use ID links during tangling
Hi, I noticed that links created during tangling back to the original Org file doesn't respect custom =org-id-link-to-org-use-id= option in ~org-babel-tangle--unbracketed-link~. I see in the comment there the reason for that, but still would prefer to use unique IDs in tangled files: the probability to overwrite wrong source block under nonunique header overweights a side-effect of creating new ID in Org file during tangling. Can we do something with this? Add another option or provide an even eager value in =org-id-link-to-org-use-id=.
[PATCH v5] ob-tangle.el: Blocks overwrite each other when grouping before tangling
Ihor Radchenko writes: >> +(ert-deftest ob-tangle/collect-blocks () >> + "Test block collection into groups for tangling." >> + (org-test-with-temp-text-in-file >> + "* H1 with :tangle in properties >> +:PROPERTIES: >> +:header-args: :tangle relative.el >> +:END: >> >> + ;; to the first header >> + (insert (format "#+begin_src emacs-lisp :tangle %s >> +\"H1: absolute org-file.lang-ext :tangle %s\" >> +#+end_src" el-file-abs el-file-abs)) >> + (goto-char (point-max)) > > This combination of pre-filled text and insertions is a bit > disorienting. I understand why you need to insert some things only after > we know the temporary Org file name, but I'd instead placed all the > contents together via insert. Rewrote. >> +#+begin_src emacs-lisp :tangle %s >> +\"H2: relative org-file.lang-ext :tangle %s\" >> +#+end_src" el-file-rel el-file-rel)) >> + (should (equal (funcall expected-targets-fn 4) >> + (funcall collected-targets-fn >> (org-babel-tangle-collect-blocks > > When reading this code, I have no idea what it is trying to test. > Probably something to do with function names not being descriptive. > At least, a comment would help. > > And the magic numbers "4" and "5" have no obvious meaning. Hope new version is cleaner. >From f1bf00592b1ee2bb27148fe93316cc6c1a192179 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Fri, 21 Jul 2023 22:40:06 +0100 Subject: [PATCH v5 1/2] testing/lisp/test-ob-tangle.el: Test block collection into groups for tangling * testing/lisp/test-ob-tangle.el (ob-tangle/collect-blocks): Test block collection into groups for tangling. --- testing/lisp/test-ob-tangle.el | 116 + 1 file changed, 116 insertions(+) diff --git a/testing/lisp/test-ob-tangle.el b/testing/lisp/test-ob-tangle.el index 07e75f4d3..ad0e1c29c 100644 --- a/testing/lisp/test-ob-tangle.el +++ b/testing/lisp/test-ob-tangle.el @@ -569,6 +569,122 @@ another block (set-buffer-modified-p nil)) (kill-buffer buffer +(ert-deftest ob-tangle/collect-blocks () + "Test block collection into groups for tangling." + (org-test-with-temp-text-in-file "" ; filled below, it depends on temp file name +(let* ((org-file (buffer-file-name)) + (test-dir (file-name-directory org-file)) + (el-file-abs (concat (file-name-sans-extension org-file) ".el")) + (el-file-rel (file-name-nondirectory el-file-abs))) + (insert (format "* H1 with :tangle in properties +:PROPERTIES: +:header-args: :tangle relative.el +:END: + +#+begin_src emacs-lisp +\"H1: inherited :tangle relative.el in properties\" +#+end_src + +#+begin_src emacs-lisp :tangle yes +\"H1: :tangle yes\" +#+end_src + +#+begin_src emacs-lisp :tangle no +\"H1: should be ignored\" +#+end_src + +#+begin_src emacs-lisp :tangle %s +\"H1: absolute org-file.lang-ext :tangle %s\" +#+end_src + +#+begin_src emacs-lisp :tangle relative.el +\"H1: :tangle relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ./relative.el +\"H1: :tangle ./relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle /tmp/absolute.el +\"H1: :tangle /tmp/absolute.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ~/../../tmp/absolute.el +\"H1: :tangle ~/../../tmp/absolute.el\" +#+end_src + +* H2 without :tangle in properties + +#+begin_src emacs-lisp +\"H2: without :tangle\" +#+end_src + +#+begin_src emacs-lisp :tangle yes +\"H2: :tangle yes\" +#+end_src + +#+begin_src emacs-lisp :tangle no +\"H2: should be ignored\" +#+end_src + +#+begin_src emacs-lisp :tangle %s +\"H2: relative org-file.lang-ext :tangle %s\" +#+end_src + +#+begin_src emacs-lisp :tangle relative.el +\"H2: :tangle relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ./relative.el +\"H2: :tangle ./relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle /tmp/absolute.el +\"H2: :tangle /tmp/absolute.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ~/../../tmp/absolute.el +\"H2: :tangle ~/../../tmp/absolute.el\" +#+end_src" el-file-abs el-file-abs el-file-rel el-file-rel)) + (letrec ((sort-fn (lambda (lst) (seq-sort-by #'car #'string-lessp lst))) + (normalize-expected-targets-alist +(lambda (blocks-per-target-alist) + "Convert to absolute file names and sort expected targets" + (funcall sort-fn + (map-apply (lambda (file nblocks) +(cons (expand-file-name file test-dir) nblocks)) + blocks-per-targe
[PATCH v4] ob-tangle.el: Blocks overwrite each other when grouping before tangling
Ihor Radchenko writes: [...] > Thanks! > The second patch is malformed. May you please resend? Sorry, resend with rewritten test. [...] > If you can, please avoid using `org-test-at-id'. This is much less > readable compared to explicit org-test-with-temp-text because one needs > to reach out to another file in order to understand what the test is > about. Now it's less verbose, handles both cases (with and without TARGET-FILE) and prints detailed ert explanation. > Evgenii Klimov writes: [...] >> It wasn't clear for me: will ":tangle yes" or explicit ":tangle no" be >> affected by TARGET-FILE. Maybe if we rephrase as follows it will be >> clear for both of us: >> >> Optional argument TARGET-FILE can be used to overwrite a default >> export file in `org-babel-default-header-args' for all source >> blocks. > > In `org-babel-tangle', TARGET-FILE is set as fallback value for the > blocks that have no :tangle value at all, including inherited; including > :tangle yes. This exactly idea I wanted to add to the docstring. > The manual asserts > > ‘yes’ > Export the code block to source file. The file name for the source > file is derived from the name of the Org file, and the file > extension is derived from the source code language identifier. > Example: ‘:tangle yes’. > > So, "yes" should imply :tangle > > `org-babel-tangle-collect-blocks' handles this by > > (unless (or (string= src-tfile "no") > (and tangle-file (not (equal tangle-file src-tfile))) > (and lang-re (not (string-match-p lang-re src-lang > > So, :tangle no is always excluded. > When TANGLE-FILE is set and not equal to :tangle value (including > "yes"), block is also excluded. Indeed, but later ‘no’ The *default*. Do not extract the code in a source code file. Example: ‘:tangle no’. in conjunction with TARGET-FILE's description in ~org-babel-tangle~ docstring: Optional argument TARGET-FILE can be used to specify a *default* export file for all source blocks. made me feel doubt about TARGET-FILE's effect. Anyway, probably it was my incorrect interpretation, so let's leave it as it is. >From a5b4faec9b58b8e56512c03e4f1a1fe295900d3f Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Fri, 21 Jul 2023 22:40:06 +0100 Subject: [PATCH v4 1/2] testing/lisp/test-ob-tangle.el: Test block collection into groups for tangling * testing/lisp/test-ob-tangle.el (ob-tangle/collect-blocks): Test block collection into groups for tangling. --- testing/lisp/test-ob-tangle.el | 111 + 1 file changed, 111 insertions(+) diff --git a/testing/lisp/test-ob-tangle.el b/testing/lisp/test-ob-tangle.el index 07e75f4d3..55e1f7aa3 100644 --- a/testing/lisp/test-ob-tangle.el +++ b/testing/lisp/test-ob-tangle.el @@ -569,6 +569,117 @@ another block (set-buffer-modified-p nil)) (kill-buffer buffer +(ert-deftest ob-tangle/collect-blocks () + "Test block collection into groups for tangling." + (org-test-with-temp-text-in-file + "* H1 with :tangle in properties +:PROPERTIES: +:header-args: :tangle relative.el +:END: + +#+begin_src emacs-lisp +\"H1: inherited :tangle relative.el in properties\" +#+end_src + +#+begin_src emacs-lisp :tangle yes +\"H1: :tangle yes\" +#+end_src + +#+begin_src emacs-lisp :tangle no +\"H1: should be ignored\" +#+end_src + + + +#+begin_src emacs-lisp :tangle relative.el +\"H1: :tangle relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ./relative.el +\"H1: :tangle ./relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle /tmp/absolute.el +\"H1: :tangle /tmp/absolute.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ~/../../tmp/absolute.el +\"H1: :tangle ~/../../tmp/absolute.el\" +#+end_src + +* H2 without :tangle in properties + +#+begin_src emacs-lisp +\"H2: without :tangle\" +#+end_src + +#+begin_src emacs-lisp :tangle yes +\"H2: :tangle yes\" +#+end_src + +#+begin_src emacs-lisp :tangle no +\"H2: should be ignored\" +#+end_src + +#+begin_src emacs-lisp :tangle relative.el +\"H2: :tangle relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ./relative.el +\"H2: :tangle ./relative.el\" +#+end_src + +#+begin_src emacs-lisp :tangle /tmp/absolute.el +\"H2: :tangle /tmp/absolute.el\" +#+end_src + +#+begin_src emacs-lisp :tangle ~/../../tmp/absolute.el +\"H2: :tangle ~/../../tmp/absolute.el\" +#+end_src +" +(letrec ((org-file (buffer-file-name)) + (test-dir (file-name-directory org-file)) + (el-file-abs (concat (file-name-sans-extension org-file) ".el")) +
[PATCH v3] ob-tangle.el: Blocks overwrite each other when grouping before tangling
Hi Here are the new tests that demonstrate the bug in block grouping during block collection, along with the patch to address the issue, taking your previous remarks into account. I split it into two patches so you can apply the tests first to see the bug. And probably tests should be rewritten as they look too complex and mostly duplicate each other. I'd appreciate your suggestions on how to enhance them. Ihor Radchenko writes: > Evgenii Klimov writes: > >> In this version I just updated the docstrings for the relevant >> functions, because prior to that it wasn't clear: does this "default >> export file for *all* source blocks" influence blocks with :tangle >> "yes"/FILENAME? > > Thanks for the patch, but we need to be careful changing things in > ob-tangle. Not everything is well-documented there. > >> Optional argument TARGET-FILE can be used to specify a default >> -export file for all source blocks. >> +export file for all source blocks without :tangle header >> +argument. > > This is confusing. > Is :tangle yes "without"? > What about inheritance? > What about default header args? I just find current lack of details confusing as well and want to express the place of TARGET-FILE in the lineage of :tangle in ~org-babel-get-src-block-info~: 1. org-babel-default-header-args 1. TANGLE-FILE of ~org-babel-tangle~ 2. org-babel-default-header-args: 3. org-babel-params-from-properties 4. org-element-property :parameters datum 5. org-element-property :header datum It wasn't clear for me: will ":tangle yes" or explicit ":tangle no" be affected by TARGET-FILE. Maybe if we rephrase as follows it will be clear for both of us: Optional argument TARGET-FILE can be used to overwrite a default export file in `org-babel-default-header-args' for all source blocks. > What if we have :tangle "/path/to/foo" and TARGET-FILE = "/path/to/foo"? > What if they are :tangle "./foo" and TARGET-FILE = "/full/path/to/foo"? See the new tests in the patch, I tried to take it into account. >> (defun org-babel-effective-tangled-filename (buffer-fn src-lang src-tfile) >> - "Return effective tangled filename of a source-code block. >> + "Return effective tangled absolute filename of a source-code block. > > This will likely cause breakage. > There are two callers of `org-babel-effective-tangled-filename: > 1. `org-babel-tangle-collect-blocks' > 2. `org-babel-tangle-single-block' > > `org-babel-tangle-single-block' passes (nth 1 result) as BUFFER-FN. > Its value is > > (if org-babel-tangle-use-relative-file-links > (file-relative-name file) > file) > > So, > >> + (let* ((fnd (file-name-directory (buffer-file-name >> +(get-buffer buffer-fn > > will fail when FILE contains file path. > And it does: (file (buffer-file-name (buffer-base-buffer))) Thanks, fixed: both `org-babel-tangle-single-block' and `org-babel-tangle-collect-blocks' now pass absolute value to `org-babel-effective-tangled-filename'. >From 7235bf0306d12f6644838ad8542ac8822bcde258 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Fri, 21 Jul 2023 22:40:06 +0100 Subject: [PATCH v3 1/2] testing/lisp/test-ob-tangle.el: Test block collection into groups for tangling * testing/lisp/test-ob-tangle.el (ob-tangle/collect-blocks): Test block collection into groups for tangling. (ob-tangle/collect-blocks-with-target-file): The same but with TARGET-FILE. --- testing/examples/babel.org | 75 ++ testing/lisp/test-ob-tangle.el | 60 +++ 2 files changed, 135 insertions(+) diff --git a/testing/examples/babel.org b/testing/examples/babel.org index d46afeb5e..2d7b39d4e 100644 --- a/testing/examples/babel.org +++ b/testing/examples/babel.org @@ -490,3 +490,78 @@ The =[[= causes a false positive which ~org-babel-detangle~ should handle proper :END: #+begin_src emacs-lisp :tangle yes :comments link #+end_src +* tangle collect blocks +:PROPERTIES: +:ID: fae6bb5b-555a-4d68-9658-a30ac5d1b2ba +:END: +** with :tangle in properties +:PROPERTIES: +:ID: b2021d51-253c-4b26-9988-dac9193eb00b +:header-args: :tangle relative.el +:END: +#+begin_src emacs-lisp +"H1: no :tangle, but :tangle relative.el in properties" +#+end_src + +#+begin_src emacs-lisp :tangle yes +"H1: :tangle yes (to babel.el)" +#+end_src + +#+begin_src emacs-lisp :tangle no +"H1: should be ignored" +#+end_src + +#+begin_src emacs-lisp :tangle ./babel.el +"H1: :tangle ./babel.el" +#+end_src + +#+begin_src emacs-lisp :tangle relative.el +"H1: :tangle relative.el" +#+end_src + +#+begin_src emacs-lisp :tangle
Re: [BUG] [PATCH] Avoid interaction in test ~ob-tangle/detangle-false-positive~
Ihor Radchenko writes: > Bastien Guerry writes: > Copyright assignment is complete. >>> >>> Bastien, may you confirm? >> >> Yes I do! Thanks for the heads up. > > Thanks! > Recorded. > https://git.sr.ht/~bzg/worg/commit/daaa35a9 Thanks, what about the patch itself?
Re: [BUG] [PATCH] Avoid interaction in test ~ob-tangle/detangle-false-positive~
Ihor Radchenko writes: > Evgenii Klimov writes: > >> Test ~ob-tangle/detangle-false-positive~ asks for confirmation to kill >> the buffer, connected to testing/examples/babel.org file, that is >> modified during the couse of the test. >> >> Way to reproduce the bug (from projects main dir): > > Thanks! > Waiting for your copyright assignment before applying. Copyright assignment is complete.
Re: Unable to unfold a folded block having point directly after the folded block
Hi Vlastimil Vondra writes: > Perfect, org-reveal is working as well, haven't known about that! But it > would be good that org-reveal is called automatically before org-cycle, > because when > going through the task list, I'm just expanding by tab. It is not really > convenient to use tab and when reaching error (or no unfold) then hitting C-c > C-r. > Maybe it's just me. [...] Can't you move the point at the beginning of the line before starting to expand by tab? That way =org-speed-commands= will be available for you and moving/expanding will be even faster.
Re: [BUG] [PATCH] Avoid interaction in test ~ob-tangle/detangle-false-positive~
Ihor Radchenko writes: > Evgenii Klimov writes: > >> Test ~ob-tangle/detangle-false-positive~ asks for confirmation to kill >> the buffer, connected to testing/examples/babel.org file, that is >> modified during the couse of the test. >> >> Way to reproduce the bug (from projects main dir): > > Thanks! > Waiting for your copyright assignment before applying. Thanks, responsible person from FSF just returned from vacation. While it's not applied, may I also ask: I noticed that non-default value 'other-frame of =org-src-window-setup= variable in my init.el leads to creation of multiple frames during interactive testing. I understand that testing should be done on ~emacs -Q~ etc, but since it's an option to quickly test interactively in the current process during development, would you accept the patch where =org-src-window-setup= would be set to default value inside the test? It took me some time to figure it out, so further developers in the similar situation could benefit from it.
[BUG] [PATCH] Avoid interaction in test ~ob-tangle/detangle-false-positive~
Test ~ob-tangle/detangle-false-positive~ asks for confirmation to kill the buffer, connected to testing/examples/babel.org file, that is modified during the couse of the test. Way to reproduce the bug (from projects main dir): #+BEGIN_SRC sh :dir (expand-file-name ".") emacs -Q \ -L lisp/ -L testing/ -L testing/lisp -l lisp/org.el \ -l lisp/org-id.el -l testing/org-test.el -l testing/lisp/test-ob-tangle.el \ --eval "(progn (org-reload) (setq org-confirm-babel-evaluate nil) \ (org-babel-do-load-languages 'org-babel-load-languages \ '((emacs-lisp . t) (shell . t) (org . t" \ --eval '(ert "ob-tangle/detangle-false-positive")' #+END_SRC >From 5905e37a581d4cf2a4a517593c91730d836b6471 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Sun, 16 Jul 2023 13:14:38 +0100 Subject: [PATCH] testing/lisp/test-ob-tangle.el: Avoid interaction in test * testing/lisp/test-ob-tangle.el (ob-tangle/detangle-false-positive): Unset modification flag from buffer to kill (testing/examples/babel.org) in tear down step of test to avoid Emacs asking for confirmation during interactive testing from within Emacs. --- testing/lisp/test-ob-tangle.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/lisp/test-ob-tangle.el b/testing/lisp/test-ob-tangle.el index b1b0a0a53..07e75f4d3 100644 --- a/testing/lisp/test-ob-tangle.el +++ b/testing/lisp/test-ob-tangle.el @@ -565,6 +565,8 @@ another block (should (equal (string-trim (org-element-property :value (org-element-at-point))) ";; detangle changes" + (with-current-buffer buffer +(set-buffer-modified-p nil)) (kill-buffer buffer (provide 'test-ob-tangle) -- 2.34.1
[PATCH worg] Fix broken link
>From ed39640d75df231c8826191f2576fcfd6a5aa723 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Sat, 15 Jul 2023 00:34:58 +0100 Subject: [PATCH] org-contrib/babel/languages/index.org: Fix broken link --- org-contrib/babel/languages/index.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org-contrib/babel/languages/index.org b/org-contrib/babel/languages/index.org index a72db778..0dc6f2f8 100644 --- a/org-contrib/babel/languages/index.org +++ b/org-contrib/babel/languages/index.org @@ -257,7 +257,7 @@ To fetch a copy of this file, please clone Worg: You should find =org-contrib/babel/ob-template.el=. -Developers are encouraged to read the [[file:../../org-contribute.org][Org-mode contribution +Developers are encouraged to read the [[file:../../../org-contribute.org][Org-mode contribution instructions]] in the hope that the language support can be added to the Org-mode core. -- 2.34.1
Re: [Pre-PATCH v2] Add the capability to specify lexical scope in tangled files (was: Add new :lexical header argument)
No Wayman writes: [...] > I, and others, have been surprised to find that the tangled file does > not have lexical binding enabled when :lexical blocks are tangled. Am I correct that language-specific header arguments are not yet covered in the manual? I can't find any reference of "lexical" there.
[Pre-PATCH] Add new :lexical header argument
Hi, here I propose new header argument to enable scope change (lexical/dynamic binding) of the tangled file. We have :shebang header argument and the new one behaves similarly. If you like the idea I think we should discuss the following: - should we allow to set it for non-elisp blocks? e.g. :shebang is not restricted and `elisp-enable-lexical-binding' is smart enough to use the comment symbol appropriate to the context. - should it be :lexical or :scope. :lexical is long to type, but boolean and clear; scope is shorter, but the user will have to type "dynamic/lexical" or "dyn/lex". - should we add the third option of the argument to explicitly forbid lexical binding? E.g. if we a have source block that rely on the dynamic binding but it could be used in another block with lexical binding via noweb. I'm not sure that it's worth the effort. - which default value to choose? Currently if you tangle it would be dynamic, but lexical binding is the future. After all I'll add tests and update Changelog/Docs if needed. >From 3ad56137cb709182dc1bc242cd80a1474078cb95 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Thu, 13 Jul 2023 18:16:08 +0100 Subject: [PATCH] ob-tangle.el: Add new :lexical header argument * lisp/ob-tangle.el (org-babel-tangle-use-lexical-binding): Add new customization variable. (org-babel-tangle): Add ability to enable lexical binding in tangled file. * lisp/ob-core.el (org-babel-common-header-args-w-values): Add new :lexical header argument. Previously one could achieve this manually, but 1) had to keep in mind to hold this source block top-most, 2) couldn't use comment header argument, as `lexical-binding' variable must be set in the first line of a file. --- lisp/ob-core.el | 1 + lisp/ob-tangle.el | 15 +-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 47410b53f..c1801a677 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -437,6 +437,7 @@ then run `org-babel-switch-to-session'." (sep . :any) (session . :any) (shebang . :any) +(lexical. ((yes no))) (tangle . ((tangle yes no :any))) (tangle-mode . ((#o755 #o555 #o444 :any))) (var . :any) diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el index 1274d0db7..916dd8489 100644 --- a/lisp/ob-tangle.el +++ b/lisp/ob-tangle.el @@ -76,6 +76,11 @@ then the name of the language is used." :group 'org-babel-tangle :type 'boolean) +(defcustom org-babel-tangle-use-lexical-binding nil + "Enable lexical binding in tangled file by default." + :group 'org-babel-tangle + :type 'boolean) + (defcustom org-babel-post-tangle-hook nil "Hook run in code files tangled by `org-babel-tangle'." :group 'org-babel-tangle @@ -262,7 +267,7 @@ expression." (when file-name (let ((lspecs (cdr by-fn)) (fnd (file-name-directory file-name)) - modes make-dir she-banged lang) + modes make-dir she-banged scoped lang) ;; drop source-blocks to file ;; We avoid append-to-file as it does not work with tramp. (with-temp-buffer @@ -273,6 +278,9 @@ expression." (get-spec (lambda (name) (cdr (assq name (nth 4 spec) (she-bang (let ((sheb (funcall get-spec :shebang))) (when (> (length sheb) 0) sheb))) + (lexicalp (or (string-equal (funcall get-spec :lexical) + "yes") + org-babel-tangle-use-lexical-binding)) (tangle-mode (funcall get-spec :tangle-mode))) (unless (string-equal block-lang lang) (setq lang block-lang) @@ -294,7 +302,10 @@ expression." (when (and she-bang (not she-banged)) (insert (concat she-bang "\n")) (setq she-banged t)) - (org-babel-spec-to-string spec) +(org-babel-spec-to-string spec) + (when (and lexicalp (not scoped)) + (save-excursion (elisp-enable-lexical-binding)) + (setq scoped t)) (setq block-counter (+ 1 block-counter lspecs) (when make-dir -- 2.34.1
[PATCH v2] ob-tangle.el: Blocks overwrite each other when grouping before tangling
In this version I just updated the docstrings for the relevant functions, because prior to that it wasn't clear: does this "default export file for *all* source blocks" influence blocks with :tangle "yes"/FILENAME? >From 1a4f76960cf11fb192f2bee2cdc8778c7b897f1a Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Wed, 12 Jul 2023 19:24:48 +0100 Subject: [PATCH v2] ob-tangle.el: Avoid relative file names when grouping blocks to tangle * lisp/ob-tangle.el (org-babel-effective-tangled-filename): Avoid using relative file names that could cause one block to overwrite the others in `org-babel-tangle-collect-blocks' if they have the same target file but in different formats. (org-babel-tangle-file, org-babel-tangle): Clarify the meaning of the TARGET-FILE argument. --- lisp/ob-tangle.el | 34 +- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el index 25129616f..1274d0db7 100644 --- a/lisp/ob-tangle.el +++ b/lisp/ob-tangle.el @@ -194,11 +194,12 @@ evaluating BODY." ;;;###autoload (defun org-babel-tangle-file (file target-file lang-re) - "Extract the bodies of source code blocks in FILE. + "Extract the bodies of source code blocks from FILE. Source code blocks are extracted with `org-babel-tangle'. Optional argument TARGET-FILE can be used to specify a default -export file for all source blocks. +export file for all source blocks without :tangle header +argument. Optional argument LANG-RE can be used to limit the exported source code blocks by languages matching a regular expression. @@ -230,9 +231,10 @@ With one universal prefix argument, only tangle the block at point. When two universal prefix arguments, only tangle blocks for the tangle file of the block at point. Optional argument TARGET-FILE can be used to specify a default -export file for all source blocks. Optional argument LANG-RE can -be used to limit the exported source code blocks by languages -matching a regular expression." +export file for all source blocks without :tangle header +argument. Optional argument LANG-RE can be used to limit the +exported source code blocks by languages matching a regular +expression." (interactive "P") (run-hooks 'org-babel-pre-tangle-hook) ;; Possibly Restrict the buffer to the current code block @@ -427,17 +429,23 @@ that the appropriate major-mode is set. SPEC has the form: org-babel-tangle-comment-format-end link-data) (defun org-babel-effective-tangled-filename (buffer-fn src-lang src-tfile) - "Return effective tangled filename of a source-code block. + "Return effective tangled absolute filename of a source-code block. BUFFER-FN is the name of the buffer, SRC-LANG the language of the block and SRC-TFILE is the value of the :tangle header argument, as computed by `org-babel-tangle-single-block'." - (let ((base-name (cond -((string= "yes" src-tfile) - ;; Use the buffer name - (file-name-sans-extension buffer-fn)) -((string= "no" src-tfile) nil) -((> (length src-tfile) 0) src-tfile))) -(ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang))) + (let* ((fnd (file-name-directory (buffer-file-name +(get-buffer buffer-fn + (base-name (cond + ((string= "yes" src-tfile) + ;; Use the buffer name + (file-name-concat fnd +(file-name-sans-extension buffer-fn))) + ((string= "no" src-tfile) nil) + ((> (length src-tfile) 0) + (if (file-name-directory src-tfile) + src-tfile +(file-name-concat fnd src-tfile) + (ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang))) (when base-name ;; decide if we want to add ext to base-name (if (and ext (string= "yes" src-tfile)) -- 2.34.1
[PATCH] ob-tangle.el: Blocks overwrite each other when grouping before tangling
And here's the patch to fix it. >From 2695d48f265a4100a9fc25c4dd278ab2b4b89ba5 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Wed, 12 Jul 2023 19:24:48 +0100 Subject: [PATCH] ob-tangle.el: Avoid relative file names when grouping blocks to tangle * lisp/ob-tangle.el (org-babel-effective-tangled-filename): Avoid using relative file names that could cause one block to overwrite the others in `org-babel-tangle-collect-blocks' if they have the same target file but in different formats. --- lisp/ob-tangle.el | 22 ++ 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el index 25129616f..4aab453e3 100644 --- a/lisp/ob-tangle.el +++ b/lisp/ob-tangle.el @@ -427,17 +427,23 @@ that the appropriate major-mode is set. SPEC has the form: org-babel-tangle-comment-format-end link-data) (defun org-babel-effective-tangled-filename (buffer-fn src-lang src-tfile) - "Return effective tangled filename of a source-code block. + "Return effective tangled absolute filename of a source-code block. BUFFER-FN is the name of the buffer, SRC-LANG the language of the block and SRC-TFILE is the value of the :tangle header argument, as computed by `org-babel-tangle-single-block'." - (let ((base-name (cond -((string= "yes" src-tfile) - ;; Use the buffer name - (file-name-sans-extension buffer-fn)) -((string= "no" src-tfile) nil) -((> (length src-tfile) 0) src-tfile))) -(ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang))) + (let* ((fnd (file-name-directory (buffer-file-name +(get-buffer buffer-fn + (base-name (cond + ((string= "yes" src-tfile) + ;; Use the buffer name + (file-name-concat fnd +(file-name-sans-extension buffer-fn))) + ((string= "no" src-tfile) nil) + ((> (length src-tfile) 0) + (if (file-name-directory src-tfile) + src-tfile +(file-name-concat fnd src-tfile) + (ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang))) (when base-name ;; decide if we want to add ext to base-name (if (and ext (string= "yes" src-tfile)) -- 2.34.1
[BUG] ob-tangle.el: Blocks overwrite each other when grouping before tangling
Hi, I noticed that during grouping of blocks to tangle some of them can overwrite each other if they have the same target file, but in different format (relative vs absolute). Consider this example (part of example.org file in the attachment): * 1st explicit :tangle yes #+begin_src emacs-lisp :tangle yes "1st explicit :tangle yes" #+end_src * 1st implicit default #+begin_src emacs-lisp "1st implicit :tangle no" #+end_src If we call `org-babel-tangle-file' with target-file arg equal to "/path/to/example.el" (e.g. `org-babel-load-file' does that), then target file name for the first block will be "example.el" and "/path/to/example.el" for the second block. It appears to be crucial in `org-babel-tangle-collect-blocks' [1]: ;; `org-babel-map-src-blocks' runs this part on each source block (let* ((block (org-babel-tangle-single-block counter)) (src-tfile (cdr (assq :tangle (nth 4 block (file-name (org-babel-effective-tangled-filename (nth 1 block) src-lang src-tfile)) (by-fn (assoc file-name blocks))) (if by-fn (setcdr by-fn (cons (cons src-lang block) (cdr by-fn))) (push (cons file-name (list (cons src-lang block))) blocks))) Current implementation of `org-babel-effective-tangled-filename' returns relative file name if :tangle is "yes" or relative FILENAME. But if :tangle happened to be absolute (as `org-babel-load-file' does), then blocks with the same file name but one name is relative while the other is absolute, will be treated as different and won't be group (see last tree lines of code above). As a result when blocks are returned to `org-babel-tangle' [2] one group will overwrite the previous one, since their absolute file names are equal. I noticed two scenarious where such things happen (e.g. if running `org-babel-tangle-file'): - if target-file arg is equal to one of :tangle FILENAMEs and some blocks don't have :tangle argument, while other have :tangle FILENAME. As a result one of these groups will be lost. - if target-file arg is equal to tangled original Org file and some blocks don't have :tangle argument, while other have :tangle "yes". As a result one of these groups will also be lost. I attach example Org file and scratch code to reproduce both scenarious. [1] [[file:lisp/ob-tangle.el::(file-name (org-babel-effective-tangled-filename][target file-name]] [2] [[file:lisp/ob-tangle.el::org-babel-tangle-collect-blocks lang-re tangle-file))][blocks return]] * 1st explicit :tangle yes #+begin_src emacs-lisp :tangle yes "1st explicit :tangle yes" #+end_src * 1st explicit :tangle filename.el #+begin_src emacs-lisp :tangle filename.el "1st explicit :tangle filename.el" #+end_src * 1st implicit default #+begin_src emacs-lisp "1st implicit :tangle no" #+end_src * 2nd explicit :tangle yes #+begin_src emacs-lisp :tangle yes "2nd explicit :tangle yes" #+end_src * explicit :tangle no #+begin_src emacs-lisp :tangle no "explicit :tangle no" #+end_src * 2nd explicit :tangle filename.el #+begin_src emacs-lisp :tangle filename.el "2nd explicit :tangle filename.el" #+end_src * 2nd implicit default #+begin_src emacs-lisp "2nd implicit :tangle no" #+end_src scratch.el Description: scratch code to reproduce the bug
Re: [PATCH] org.el: Remove undefined dynamic variable `org-log-states' from example
Ihor Radchenko writes: > It looks like 5 working days have passed since your email to FSF. If so, > please follow up once and wait another 5 working days. I've got papers from FSF, signed it and sent it back. It was 6 working days ago. 5 days that you mention is for the first response from them, I guess?
[PATCH] org.el: Remove undefined dynamic variable `org-log-states' from example
I added `org-summary-todo' example function, that are advertized in `org-after-todo-statistics-hook', to my init file (with lexical-binding: t) and got a compilation warning: Warning (bytecomp): Unused lexical variable `org-log-states' since this variable is undefined. The command: git log -G 'org-log-states[^-]' --patch -- lisp/ shows its first appearance in commit 2c0812caf14e674d938d80d05678576c0cefcc83 but only in docstring. Running ~find~ also didn't show its definition: find -H . -type f -exec grep --color=auto -i -nH --null \ -e org-log-states\[\^-\] \{\} + But there are =org-log-states-order-reversed=, but it doesn't seem to be relevant. PS: I didn't add TINYCHANGE since I have reached the contribution limit but FSF didn't respond yet. >From a3e50c5799acb216ccb2c1ae6883d73ac36e4291 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Mon, 10 Jul 2023 23:00:41 +0100 Subject: [PATCH] org.el: Remove undefined dynamic variable `org-log-states' from example * lisp/org.el (org-after-todo-statistics-hook): Remove undefined dynamic variable `org-log-states' from docstring example. * doc/org-manual.org (Breaking Down Tasks into Subtasks): The same thing in doc example. `org-log-states' was never defined throughout the whole repo history, its removal helps to avoid compilation warning. --- doc/org-manual.org | 2 +- lisp/org.el| 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 987a29354..8a58bb31e 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -4648,7 +4648,7 @@ all children are done, you can use the following setup: #+begin_src emacs-lisp (defun org-summary-todo (n-done n-not-done) "Switch entry to DONE when all subentries are done, to TODO otherwise." - (let (org-log-done org-log-states) ; turn off logging + (let (org-log-done) ; turn off logging (org-todo (if (= n-not-done 0) "DONE" "TODO" (add-hook 'org-after-todo-statistics-hook #'org-summary-todo) diff --git a/lisp/org.el b/lisp/org.el index 62278ec77..9df56c700 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -9755,7 +9755,7 @@ when there is a statistics cookie in the headline! (defun org-summary-todo (n-done n-not-done) \"Switch entry to DONE when all subentries are done, to TODO otherwise.\" - (let (org-log-done org-log-states) ; turn off logging + (let (org-log-done) ; turn off logging (org-todo (if (= n-not-done 0) \"DONE\" \"TODO\"") (defvar org-todo-statistics-hook nil -- 2.34.1
Re: [PATCH v3] lisp/org.el: Add final hooks to S-/M-/S-M-cursor commands
Ihor Radchenko writes: [...] > > Thanks! > Applied, onto main. Thanks, it's a great pleasure! > Note that you have reached the contribution limit allowed without FSF > copyright assignment. If you want to contribute further, please consider > signing copyright paperwork. See > https://orgmode.org/worg/org-contribute.html#copyright Paperwork in process.
[PATCH v3] lisp/org.el: Add final hooks to S-/M-/S-M-cursor commands
Ihor Radchenko writes: > Evgenii Klimov writes: [...] > Few comments. > > First, please add Changelog entry for etc/ORG-NEWS. Done. >> +(defvar org-metaleft-final-hook nil >> + "Hook for functions attaching themselves to `M-left'. >> +See `org-ctrl-c-ctrl-c-hook' for more information.") > > Note that unlike the docstring your added, `org-shiftup-final-hook' > specifies when the hook is executed: > > (defvar org-shiftup-final-hook nil > "Hook for functions attaching themselves to `S-up'. > This one runs after all other options except shift-select have been excluded. > See `org-ctrl-c-ctrl-c-hook' for more information.") > > It is better to follow the pattern and clarify the purpose of the hook > better instead of leaving docstrings for both the -final and other hook > same. Done. >> +individual commands for more information. >> + >> +This function runs the hook `org-shiftmetaleft-hook' as a first >> +step, `org-shiftmetaleft-final-hook' as the penultimate step, and >> +returns at first non-nil value." > > Upon looking closer, I realized that you also defined return value of > the function here. Is there any particular reason for this? The return > value is currently not defined and supposed to be discarded. > Apparently the original wording is quite confusing. > What it is supposed to say is: > > This function runs the functions in `org-metaleft-hook' one by one > as a first step, and exits immediately if a function from the hook > returns non-nil. Reworded as we discussed. Also for commands that support `shift-select-mode' (i.e. org-shift{up,down,right,left}) mentioned it and `org-support-shift-select'. >From b27b95efbad7645d7bd4870becd112abc25c9840 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Thu, 29 Jun 2023 20:06:33 +0100 Subject: [PATCH v3] lisp/org.el: Add final hooks to S-/M-/S-M-cursor commands * lisp/org.el (org-metaleft-final-hook, org-metaright-final-hook, org-metaup-final-hook, org-metadown-final-hook): Define final hooks for S-cursor commands. (org-metaleft, org-metaright, org-metaup, org-metadown): Add final hooks to M-commands and document them in the docstring. * lisp/org.el (org-shiftup, org-shiftdown, org-shiftright, org-shiftleft): Document hooks for S-cursor commands in the docstring. * lisp/org.el (org-shiftmetaleft-final-hook, org-shiftmetaright-final-hook, org-shiftmetaup-final-hook, org-shiftmetadown-final-hook): Define final hooks for the S-M-cursor commands. (org-shiftmetaleft, org-shiftmetaright, org-shiftmetaup, org-shiftmetadown): Add final hooks to the S-M-cursor commands and document hooks in the docstring. * etc/ORG-NEWS (New final hooks for Modifier-Cursor keys): Document new hooks. TINYCHANGE --- etc/ORG-NEWS | 17 ++ lisp/org.el | 155 +-- 2 files changed, 156 insertions(+), 16 deletions(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index d04e92275..973a97a2f 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -437,6 +437,23 @@ Currently implemented options are: iCalendar programs support this usage. ** New features +*** New final hooks for Modifier-Cursor keys + +Final hooks are added to the following commands: +- ~org-metaleft-final-hook~ to ~org-metaleft~ (bound to =M-=). +- ~org-metaright-final-hook~ to ~org-metaright~ (bound to + =M-=). +- ~org-metaup-final-hook~ to ~org-metaup~ (bound to =M-=). +- ~org-metadown-final-hook~ to ~org-metadown~ (bound to =M-=). +- ~org-shiftmetaleft-final-hook~ to ~org-shiftmetaleft~ (bound to + =M-S-=). +- ~org-shiftmetaright-final-hook~ to ~org-shiftmetaright~ (bound to + =M-S-=). +- ~org-shiftmetaup-final-hook~ to ~org-shiftmetaup~ (bound to + =M-S-=). +- ~org-shiftmetadown-final-hook~ to ~org-shiftmetadown~ (bound to + =M-S-=). + *** ~org-insert-todo-heading-respect-content~ now accepts prefix arguments The prefix arguments are passed to ~org-insert-todo-heading~. diff --git a/lisp/org.el b/lisp/org.el index 36235322d..57d8082e5 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -16658,27 +16658,63 @@ before indentation and \t insertion takes place.") (defvar org-metaleft-hook nil "Hook for functions attaching themselves to `M-left'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaleft-final-hook nil + "Hook for functions attaching themselves to `M-left'. +This one runs after all options have been excluded. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metaright-hook nil "Hook for functions attaching themselves to `M-right'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaright-final-hook nil + "Hook for functions attaching themselves to `M-right'. +This one runs after all options have been excluded. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defv
Re: [PATCH v2] Keep the link if the command was cancelled
Ihor Radchenko writes: > Evgenii Klimov writes: > [...] >> -(when (funcall (if (equal complete-file '(64)) 'not 'identity) >> - (not org-link-keep-stored-after-insertion)) >> - (setq org-stored-links (delq (assoc link org-stored-links) >> - org-stored-links))) >> - >> (when (and (string-match org-link-plain-re link) >> (not (string-match org-ts-regexp link))) >>;; URL-like link, normalize the use of angular brackets. >> @@ -1995,6 +1990,10 @@ Use TAB to complete link prefixes, then RET for >> type-specific completion support >> (read-string "Description: " initial-input) >> initial-input))) > > The code below the removed form can modify `link' variable. If such > modification does happen, your patch will fail to remove the link from > `org-stored-links' - (assoc link org-stored-links) will no longer return > non-nil. I added `link-original' variable to keep it intact until we want to remove the link from `org-stored-links'. >From a5ff8d4fe27fd503a6ddb719a622a980a73789a7 Mon Sep 17 00:00:00 2001 From: Evgenii Klimov Date: Fri, 30 Jun 2023 22:56:39 +0100 Subject: [PATCH] Keep the link if it was not inserted * lisp/ol.el (org-insert-link): Keep the link in `org-stored-links' if the command was interrupted by the user during the reading of a description from the minibuffer. --- lisp/ol.el | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/ol.el b/lisp/ol.el index e2bf90acd..1490bde86 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1820,7 +1820,7 @@ non-interactively, don't allow to edit the default description." (all-prefixes (append (mapcar #'car abbrevs) (mapcar #'car org-link-abbrev-alist) (org-link-types))) - entry) + entry link-original) (cond (link-location) ; specified by arg, just use it. ((org-in-regexp org-link-bracket-re 1) @@ -1896,11 +1896,7 @@ Use TAB to complete link prefixes, then RET for type-specific completion support (or entry (push link org-link--insert-history)) (setq desc (or desc (nth 1 entry) -(when (funcall (if (equal complete-file '(64)) 'not 'identity) - (not org-link-keep-stored-after-insertion)) - (setq org-stored-links (delq (assoc link org-stored-links) - org-stored-links))) - +(setq link-original link) (when (and (string-match org-link-plain-re link) (not (string-match org-ts-regexp link))) ;; URL-like link, normalize the use of angular brackets. @@ -1995,6 +1991,10 @@ Use TAB to complete link prefixes, then RET for type-specific completion support (read-string "Description: " initial-input) initial-input))) +(when (funcall (if (equal complete-file '(64)) 'not 'identity) + (not org-link-keep-stored-after-insertion)) + (setq org-stored-links (delq (assoc link-original org-stored-links) + org-stored-links))) (unless (org-string-nw-p desc) (setq desc nil)) (when remove (apply #'delete-region remove)) (insert (org-link-make-string link desc)) -- 2.34.1
Re: [PATCH v2] lisp/org.el: Add final hooks to S-/M-/S-M-cursor commands
Ihor Radchenko writes: [...] >> +individual commands for more information. >> + >> +This function runs the hook `org-shiftmetaleft-hook' as a first >> +step, `org-shiftmetaleft-final-hook' as the penultimate step, and >> +returns at first non-nil value." > > Upon looking closer, I realized that you also defined return value of > the function here. Is there any particular reason for this? The return > value is currently not defined and supposed to be discarded. Maybe I got it wrong, but I tried to follow the docstring for `org-metaleft'. And I don't see here the use of the return value either: #+begin_example (defun org-metaleft ( _arg) "... This function runs the hook `org-metaleft-hook' as a first step, and returns at first non-nil value." ...) #+end_example Should I keep it like this? This function runs the hook `org-shiftmetaleft-hook' as a first step, and `org-shiftmetaleft-final-hook' as the penultimate step.
Re: [PATCH] Keep the link if the command was cancelled
Ihor Radchenko writes: > Max Nikulin writes: [...] >> I had it in mind when I was writing my message. I had even tried to find >> another command that allows to remove stored links. > > If necessary, removing stored links without inserting can be made as an > effect of negative prefix argument in `org-insert-link' or in > `org-insert-all-links'. I tried `org-insert-link' with the negative prefix argument, but the link was inserted though. And this behaviour is not mentioned in the docstring.
Re: [PATCH] Keep the link if the command was cancelled
Ihor Radchenko writes: > Evgenii Klimov writes: >> ... > > This makes sense, but the patch may break removing stored link in > certain scenarios. Thanks for response, I'll look into this issue and try to avoid this breakage.
[PATCH v2] lisp/org.el: Add final hooks to S-/M-/S-M-cursor commands
* lisp/org.el (org-metaleft-final-hook, org-metaright-final-hook, org-metaup-final-hook, org-metadown-final-hook): Define final hooks for S-cursor commands. (org-metaleft, org-metaright, org-metaup, org-metadown): Add final hooks to M-commands and document them in the docstring. * lisp/org.el (org-shiftup, org-shiftdown, org-shiftright, org-shiftleft): Document hooks for S-cursor commands in the docstring. * lisp/org.el (org-shiftmetaleft-final-hook, org-shiftmetaright-final-hook, org-shiftmetaup-final-hook, org-shiftmetadown-final-hook): Define final hooks for the S-M-cursor commands. (org-shiftmetaleft, org-shiftmetaright, org-shiftmetaup, org-shiftmetadown): Add final hooks to the S-M-cursor commands and document hooks in the docstring. TINYCHANGE --- Probably you are right and there's no need to add the final hook to `org-meta-return'. Previously, I thought that the last condition fully simulate C-RET, but the latter turned out to be `org-insert-heading-respect-content'. etc/ORG-NEWS | 17 + lisp/org.el | 98 +--- 2 files changed, 103 insertions(+), 12 deletions(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index cb4bc632b..f88e3df3d 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -249,6 +249,23 @@ Currently implemented options are: iCalendar programs support this usage. ** New features +*** New final hooks for Modifier-Cursor keys + +Final hooks are added to the following commands: +- ~org-metaleft-final-hook~ to ~org-metaleft~ (bound to =M-=). +- ~org-metaright-final-hook~ to ~org-metaright~ (bound to + =M-=). +- ~org-metaup-final-hook~ to ~org-metaup~ (bound to =M-=). +- ~org-metadown-final-hook~ to ~org-metadown~ (bound to =M-=). +- ~org-shiftmetaleft-final-hook~ to ~org-shiftmetaleft~ (bound to + =M-S-=). +- ~org-shiftmetaright-final-hook~ to ~org-shiftmetaright~ (bound to + =M-S-=). +- ~org-shiftmetaup-final-hook~ to ~org-shiftmetaup~ (bound to + =M-S-=). +- ~org-shiftmetadown-final-hook~ to ~org-shiftmetadown~ (bound to + =M-S-=). + *** ~org-insert-todo-heading-respect-content~ now accepts prefix arguments The prefix arguments are passed to ~org-insert-todo-heading~. diff --git a/lisp/org.el b/lisp/org.el index fdb920864..052c592ed 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -16831,27 +16831,51 @@ before indentation and \t insertion takes place.") (defvar org-metaleft-hook nil "Hook for functions attaching themselves to `M-left'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaleft-final-hook nil + "Hook for functions attaching themselves to `M-left'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metaright-hook nil "Hook for functions attaching themselves to `M-right'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaright-final-hook nil + "Hook for functions attaching themselves to `M-right'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metaup-hook nil "Hook for functions attaching themselves to `M-up'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaup-final-hook nil + "Hook for functions attaching themselves to `M-up'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metadown-hook nil "Hook for functions attaching themselves to `M-down'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metadown-final-hook nil + "Hook for functions attaching themselves to `M-down'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaleft-hook nil "Hook for functions attaching themselves to `M-S-left'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetaleft-final-hook nil + "Hook for functions attaching themselves to `M-S-left'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaright-hook nil "Hook for functions attaching themselves to `M-S-right'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetaright-final-hook nil + "Hook for functions attaching themselves to `M-S-right'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaup-hook nil "Hook for functions attaching themselves to `M-S-up'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetaup-final-hook nil + "Hook for functions attaching themselves to `M-S-up'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetadown-hook nil "Hook for functions attaching themselves to `M-S-down'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetadown-final-hook nil + "Hook for functions attaching themselves to `M-S-down'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metareturn-hook nil "Hook for functions attaching themselves to `M-RET'. See `org-ctrl-c-ctrl-c-hook' for more information.") @@ -16919,7 +16943,11 @@ When ARG is a numeric prefix, show contents of this level." "Promote subtree or
Re: Add final hooks to S-/M-/S-M-cursor commands
On July 1, 2023 11:40:07 AM GMT+01:00, Ihor Radchenko wrote: >Thanks for the patch! >May you please squash it into one > Don't you mind if I also add the final hook to `org-meta-return'? I didn't do it right away because it requires a little bit of refactoring: everything after the initial hook is currently run with `call-interactively'.
[PATCH] Keep the link if the command was cancelled
* lisp/ol.el (org-insert-link): Keep the link in `org-stored-links' if the command was interrupted by the user during the reading of a description from the minibuffer. --- Currently the link is lost if the user chooses the link but cancells the comand while writing the description. lisp/ol.el | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lisp/ol.el b/lisp/ol.el index e2bf90acd..e48138ef9 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1896,11 +1896,6 @@ Use TAB to complete link prefixes, then RET for type-specific completion support (or entry (push link org-link--insert-history)) (setq desc (or desc (nth 1 entry) -(when (funcall (if (equal complete-file '(64)) 'not 'identity) - (not org-link-keep-stored-after-insertion)) - (setq org-stored-links (delq (assoc link org-stored-links) - org-stored-links))) - (when (and (string-match org-link-plain-re link) (not (string-match org-ts-regexp link))) ;; URL-like link, normalize the use of angular brackets. @@ -1995,6 +1990,10 @@ Use TAB to complete link prefixes, then RET for type-specific completion support (read-string "Description: " initial-input) initial-input))) +(when (funcall (if (equal complete-file '(64)) 'not 'identity) + (not org-link-keep-stored-after-insertion)) + (setq org-stored-links (delq (assoc link org-stored-links) + org-stored-links))) (unless (org-string-nw-p desc) (setq desc nil)) (when remove (apply #'delete-region remove)) (insert (org-link-make-string link desc)) -- 2.34.1
[PATCH 2/3] lisp/org.el: Fix docstring for S-cursor commands
* lisp/org.el (org-shiftup, org-shiftdown, org-shiftright, org-shiftleft): Document hooks for S-cursor commands in the docstring. --- lisp/org.el | 24 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index b396456a2..bf61062b1 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -17121,7 +17121,11 @@ first non-nil value." "Act on current element according to context. Call `org-timestamp-up' or `org-priority-up', or `org-previous-item', or `org-table-move-cell-up'. See the -individual commands for more information." +individual commands for more information. + +This function runs the hook `org-shiftup-hook' as a first step, +`org-shiftup-final-hook' as the penultimate step, and returns at +first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-shiftup-hook)) @@ -17149,7 +17153,11 @@ individual commands for more information." "Act on current element according to context. Call `org-timestamp-down' or `org-priority-down', or `org-next-item', or `org-table-move-cell-down'. See the -individual commands for more information." +individual commands for more information. + +This function runs the hook `org-shiftdown-hook' as a first step, +`org-shiftdown-final-hook' as the penultimate step, and returns +at first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-shiftdown-hook)) @@ -17182,7 +17190,11 @@ This does one of the following: - on an item, switch entire list to the next bullet type - on a property line, switch to the next allowed value - on a clocktable definition line, move time block into the future -- in a table, move a single cell right" +- in a table, move a single cell right + +This function runs the hook `org-shiftright-hook' as a first +step, `org-shiftright-final-hook' as the penultimate step, and +returns at first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-shiftright-hook)) @@ -17222,7 +17234,11 @@ This does one of the following: - on an item, switch entire list to the previous bullet type - on a property line, switch to the previous allowed value - on a clocktable definition line, move time block into the past -- in a table, move a single cell left" +- in a table, move a single cell left + +This function runs the hook `org-shiftleft-hook' as a first step, +`org-shiftleft-final-hook' as the penultimate step, and returns +at first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-shiftleft-hook)) -- 2.34.1
Add final hooks to S-/M-/S-M-cursor commands
`org-shiftup' and other S-cursor commands not only provide initial hooks but also final hooks, while M-cursor and S-M-cursor commands lack them. These patches add final hooks to all of these commands and document both hooks in the docstring if they are not already present.
[PATCH 3/3] lisp/org.el: Add final hooks to the S-M-cursor commands
* lisp/org.el (org-shiftmetaleft-final-hook, org-shiftmetaright-final-hook, org-shiftmetaup-final-hook, org-shiftmetadown-final-hook): Define final hooks for the S-M-cursor commands. (org-shiftmetaleft, org-shiftmetaright, org-shiftmetaup, org-shiftmetadown): Add final hooks to the S-M-cursor commands and document hooks in the docstring. --- lisp/org.el | 40 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index bf61062b1..326d3eed9 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -16738,15 +16738,27 @@ See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaleft-hook nil "Hook for functions attaching themselves to `M-S-left'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetaleft-final-hook nil + "Hook for functions attaching themselves to `M-S-left'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaright-hook nil "Hook for functions attaching themselves to `M-S-right'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetaright-final-hook nil + "Hook for functions attaching themselves to `M-S-right'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaup-hook nil "Hook for functions attaching themselves to `M-S-up'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetaup-final-hook nil + "Hook for functions attaching themselves to `M-S-up'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetadown-hook nil "Hook for functions attaching themselves to `M-S-down'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-shiftmetadown-final-hook nil + "Hook for functions attaching themselves to `M-S-down'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metareturn-hook nil "Hook for functions attaching themselves to `M-RET'. See `org-ctrl-c-ctrl-c-hook' for more information.") @@ -16814,7 +16826,11 @@ When ARG is a numeric prefix, show contents of this level." "Promote subtree or delete table column. Calls `org-promote-subtree', `org-outdent-item-tree', or `org-table-delete-column', depending on context. See the -individual commands for more information." +individual commands for more information. + +This function runs the hook `org-shiftmetaleft-hook' as a first +step, `org-shiftmetaleft-final-hook' as the penultimate step, and +returns at first non-nil value." (interactive) (cond ((and (eq system-type 'darwin) @@ -16828,13 +16844,18 @@ individual commands for more information." (save-excursion (goto-char (region-beginning)) (org-at-item-p))) (call-interactively 'org-outdent-item-tree)) + ((run-hook-with-args-until-success 'org-shiftmetaleft-final-hook)) (t (org-modifier-cursor-error (defun org-shiftmetaright () "Demote subtree or insert table column. Calls `org-demote-subtree', `org-indent-item-tree', or `org-table-insert-column', depending on context. See the -individual commands for more information." +individual commands for more information. + +This function runs the hook `org-shiftmetaright-hook' as a first +step, `org-shiftmetaright-final-hook' as the penultimate step, +and returns at first non-nil value." (interactive) (cond ((and (eq system-type 'darwin) @@ -16848,6 +16869,7 @@ individual commands for more information." (save-excursion (goto-char (region-beginning)) (org-at-item-p))) (call-interactively 'org-indent-item-tree)) + ((run-hook-with-args-until-success 'org-shiftmetaright-final-hook)) (t (org-modifier-cursor-error (defun org-shiftmetaup ( _arg) @@ -16855,13 +16877,18 @@ individual commands for more information." In a table, kill the current row. On a clock timestamp, update the value of the timestamp like `S-' but also adjust the previous clocked item in the clock history. -Everywhere else, drag the line at point up." +Everywhere else, drag the line at point up. + +This function runs the hook `org-shiftmetaup-hook' as a first +step, `org-shiftmetaup-final-hook' as the penultimate step, and +returns at first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-shiftmetaup-hook)) ((org-at-table-p) (call-interactively 'org-table-kill-row)) ((org-at-clock-log-p) (let ((org-clock-adjust-closest t)) (call-interactively 'org-timestamp-up))) + ((run-hook-with-args-until-success 'org-shiftmetaup-final-hook)) (t (call-interactively 'org-drag-line-backward (defun org-shiftmetadown ( _arg) @@ -16869,13 +16896,18 @@ Everywhere else, drag the line at point up." In a table, insert an empty row at the current line. On a clock timestamp, update the value of the timestamp like `S-' but also adjust the previous clocked item in the clock history. -Everywhere else, drag the line at point down." +Everywhere
[PATCH 1/3] lisp/org.el: Add final hooks to the M-cursor commands
* lisp/org.el (org-metaleft-final-hook, org-metaright-final-hook, org-metaup-final-hook, org-metadown-final-hook): Define final hooks for S-cursor commands. (org-metaleft, org-metaright, org-metaup, org-metadown): Add final hooks to M-commands and document them in the docstring. --- lisp/org.el | 34 ++ 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 4063ba98f..b396456a2 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -16714,15 +16714,27 @@ before indentation and \t insertion takes place.") (defvar org-metaleft-hook nil "Hook for functions attaching themselves to `M-left'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaleft-final-hook nil + "Hook for functions attaching themselves to `M-left'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metaright-hook nil "Hook for functions attaching themselves to `M-right'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaright-final-hook nil + "Hook for functions attaching themselves to `M-right'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metaup-hook nil "Hook for functions attaching themselves to `M-up'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metaup-final-hook nil + "Hook for functions attaching themselves to `M-up'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-metadown-hook nil "Hook for functions attaching themselves to `M-down'. See `org-ctrl-c-ctrl-c-hook' for more information.") +(defvar org-metadown-final-hook nil + "Hook for functions attaching themselves to `M-down'. +See `org-ctrl-c-ctrl-c-hook' for more information.") (defvar org-shiftmetaleft-hook nil "Hook for functions attaching themselves to `M-S-left'. See `org-ctrl-c-ctrl-c-hook' for more information.") @@ -16879,7 +16891,8 @@ default `backward-word'. See the individual commands for more information. This function runs the hook `org-metaleft-hook' as a first step, -and returns at first non-nil value." +`org-metaleft-final-hook' as the penultimate step, and returns at +first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-metaleft-hook)) @@ -16902,6 +16915,7 @@ and returns at first non-nil value." (org-at-item-p (when (org-check-for-hidden 'items) (org-hidden-tree-error)) (call-interactively 'org-outdent-item)) + ((run-hook-with-args-until-success 'org-metaleft-final-hook)) (t (call-interactively 'backward-word (defun org-metaright ( _arg) @@ -16915,7 +16929,8 @@ With no specific context, calls the Emacs default `forward-word'. See the individual commands for more information. This function runs the hook `org-metaright-hook' as a first step, -and returns at first non-nil value." +`org-metaright-final-hook' as the penultimate step, and returns +at first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-metaright-hook)) @@ -16940,6 +16955,7 @@ and returns at first non-nil value." (org-at-item-p (when (org-check-for-hidden 'items) (org-hidden-tree-error)) (call-interactively 'org-indent-item)) + ((run-hook-with-args-until-success 'org-metaright-final-hook)) (t (call-interactively 'forward-word (defun org-check-for-hidden (what) @@ -16973,7 +16989,11 @@ this function returns t, nil otherwise." "Move subtree up or move table row up. Calls `org-move-subtree-up' or `org-table-move-row' or `org-move-item-up', depending on context. See the individual commands -for more information." +for more information. + +This function runs the hook `org-metaup-hook' as a first step, +`org-metaup-final-hook' as the penultimate step, and returns at +first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-metaup-hook)) @@ -17030,13 +17050,18 @@ for more information." (org-drag-element-backward)) ((org-at-heading-p) (call-interactively 'org-move-subtree-up)) ((org-at-item-p) (call-interactively 'org-move-item-up)) + ((run-hook-with-args-until-success 'org-metaup-final-hook)) (t (org-drag-element-backward (defun org-metadown ( _arg) "Move subtree down or move table row down. Calls `org-move-subtree-down' or `org-table-move-row' or `org-move-item-down', depending on context. See the individual -commands for more information." +commands for more information. + +This function runs the hook `org-metadown-hook' as a first step, +`org-metadown-final-hook' as the penultimate step, and returns at +first non-nil value." (interactive "P") (cond ((run-hook-with-args-until-success 'org-metadown-hook)) @@ -17089,6 +17114,7 @@ commands for more information." (org-drag-element-forward)) ((org-at-heading-p) (call-interactively 'org-move-subtree-down)) ((org-at-item-p) (call-interactively 'org-move-item-down)) +