Good news, everyone!

Emacs  : GNU Emacs 30.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version
3.24.38, cairo version 1.16.0) of 2025-04-04, modified by Debian
Package: Org mode version 9.7.31 (9.7.31-??-4e6d38d1a @
 ~/.config/emacs.doom/.local/straight/build-30.1/org/)

Currently there is a possibility to use =:comments noweb= header option
in src block, that adds comments with links to source block to the
tangled files. And this option works great with ~org-babel-detangle~ in
simple cases, but it fails to work in more complex ones.

This example of two continuous source blocks works well with detangle:

#+begin_src bash :tangle example.sh
echo "hello"
#+end_example

#+begin_src bash :tangle example.sh
echo "world"
#+end_example

The resulting file looks like

#+begin_src bash
# [[file:src.org::1][1]]
echo "hello"
# 1 ends here
# [[file:src.org::2][2]]
echo "world"
# 2 ends here
#+end_example

But following example fails:

#+begin_src bash :tangle example.sh :noweb yes :comments noweb
echo "begin"
<<first>>
echo "middle"
<<second>>
echo "end"
#+end_example

#+begin_src bash :noweb-ref first
echo "first"
#+end_example

#+begin_src bash :noweb-ref second
echo "second"
#+end_example

#+begin_src bash :noweb-ref second
echo "third"
#+end_example

The resulting file will looks like

#+begin_src bash
# [[file:src.org::1][1]]
echo "begin"
# [[file:src.org::2][2]]
echo "first"
# 2 ends here
echo "middle"
# [[file:src.org::3][3]]
echo "second"
# 3 ends here
# [[file:src.org::4][4]]
echo "third"
# 4 ends here
echo "end"
# 1 ends here
#+end_example

This comments do not have enough information to properly detangle the
file back to source blocks. So my proposal is to add the information
required for proper bidirectional navigation between the tangled file
and it's source. And this information is markers that shows where the noweb
references starts and ends, so we were able to differ if source blocks
were tangled with same noweb-ref or different.

I also propose to not use links for blocks reference, but line-numbers
of where block starts in org-file. As far as it's not possible to fill
the same tangled file from different org-files, I propose to make
special comment line with the file where it was tangled from. Thus
comments will be shorter and easier to view (org-links not working in
source files anyway).

All this could work this way only when =:comments noweb= option is used,
=:comments link= could work as it's working now.

Tangled file should be something like this:

#+begin_src bash
# ORG-FILE src.org
# SRC 1
echo "begin"
# NOWEB <<first>>
# SRC 2
echo "first"
# SRC 2 ends here
# NOWEB <<first>> ends here
echo "middle"
# NOWEB <<second>>
# SRC 3
echo "second"
# SRC 3 ends here
# SRC 4
echo "third"
# SRC 4 ends here
# NOWEB <<second>> ends here
echo "end"
# SRC 1 ends here
#+end_example

In comments it have following information:
- where to find the org-file this file was tangled from (=ORG-FILE
  filepath=)
- where to find source block with sources (=SRC line-in-org-file= and
  =SRC line-in-org-file ends here=) 
- the borders of noweb references (=NOWEB noweb-ref= and =NOWEB
  noweb-ref ends here=) 

To acheive such result we need to modify the
~org-babel-expand-noweb-reference~ function to not just insert the
source blocks links, but also adding the noweb reference begin/end
comments lines to tangled file.

Detangle function ~org-babel-detangle~ with such structure of comments
will have enough information to properly detangle source blocks using
the following algorithm: 

1. Load tangled file content to temporary buffer
2. Find first source block that do not have any comment lines started
   with =SRC= and =NOWEB= (the leaves of noweb source blocks tree) inside. 
3. If found
  3.1. detangle that source block and remove it from processing buffer
  3.2. go to step 2.
4. If not found
  4.1. find the pair of comments started with =NOWEB= and apropriate
       noweb reference
  4.2. If found
    4.2.1. it should be empty between those comments
    4.2.2. replace those comments lines with the apropriate noweb
           reference code 
    4.2.3. go to step 2.
  4.3. If not found
    4.3.1. Complete

Here is the log of changes to file processed by this algorithm. After
the first iteration the source block 2 will be detangled and removed: 

#+begin_example bash
# ORG-FILE src.org
# SRC 1
echo "begin"
# NOWEB <<first>>
# NOWEB <<first>> ends here
echo "middle"
# NOWEB <<second>>
# SRC 3
echo "second"
# SRC 3 ends here
# SRC 4
echo "third"
# SRC 4 ends here
# NOWEB <<second>> ends here
echo "end"
# SRC 1 ends here
#+end_example

Then source block 3 will be detangled and removed:

#+begin_example bash
# ORG-FILE src.org
# SRC 1
echo "begin"
# NOWEB <<first>>
# NOWEB <<first>> ends here
echo "middle"
# NOWEB <<second>>
# SRC 4
echo "third"
# SRC 4 ends here
# NOWEB <<second>> ends here
echo "end"
# SRC 1 ends here
#+end_example

Then source block 4 will be detangled and removed:

#+begin_example bash
# ORG-FILE src.org
# SRC 1
echo "begin"
# NOWEB <<first>>
# NOWEB <<first>> ends here
echo "middle"
# NOWEB <<second>>
# NOWEB <<second>> ends here
echo "end"
# SRC 1 ends here
#+end_example

Then noweb reference =<<first>>= will be recovered:

#+begin_example bash
# ORG-FILE src.org
# SRC 1
echo "begin"
<<first>>
echo "middle"
# NOWEB <<second>>
# NOWEB <<second>> ends here
echo "end"
# SRC 1 ends here
#+end_example

Then noweb reference =<<second>>= will be recovered:

#+begin_example bash
# ORG-FILE src.org
# SRC 1
echo "begin"
<<first>>
echo "middle"
<<second>>
echo "end"
# SRC 1 ends here
#+end_example

Now source block 1 can be detangled:

#+begin_example bash
# ORG-FILE src.org
#+end_example

And detangling complete.

--
Looking forward for your message,
Konstantin

Reply via email to