Hello again, sorry for the delay - I had some holiday time off
that couldn't wait ;-)

I've modified the ob-tangle.el file for the main tangling and
detangling functions.  Most importantly, both functions can now
exchange information from the source Org mode file to the target
remote tangle file in either direction, depending on whether the
source Org file has `:tangle-sync <action>' in the header.

The action is one of:

- "export" = always transmit information from the source Org mode
             block to the target remote file.
- "import" = always transmit information from the target remote
             file to the source Org mode block.
- "skip" = skip the block.
- "both" = transmit information from source block to target block
           or target block to source, depending on whether the
           tangle or detangle is called from the source buffer or
           the target buffer respectively.

These functions work at the whole buffer and at the per-block
level.  The `org-babel-tangle-sync' functions automate this
process by hooking into the `after-save-hook' and tangling /
detangling the current block.

I feel that I should write what the main motivation for this is:
Dotfiles that are always in sync with the org-mode files they
stem from.

Hope this turns into something big!
Best,

Mehmet
From 6fad6251104c1d9ac33071328c034def868fa38e Mon Sep 17 00:00:00 2001
From: MT <mtekman89@gmail.com>
Date: Tue, 2 May 2023 18:16:39 +0200
Subject: [PATCH 5/6] lisp/ob-tangle-sync.el: Automatic synchronization of
 tangled blocks

* ob-tangle-sync.el (org-babel-tangle-sync-mode,
org-babel-tangle-sync-synchronize): A new global minor mode that
hooks into the `after-save-hook' in every buffer and runs
`org-babel-tangle-sync-synchronize' which calls either
`org-babel-detangle-single-block' or `C-u C-u org-babel-tangle'
depending on whether it is in the source org mode file or the remote
tangle file.  It avoids writing directly to file where possible and
prefers inplace buffer changes.
(org-babel-tangle-sync-files): A custom list of org-mode files which
to run the synchronization on.  If nil, then all files that have
tangled and detangleable contents are operated on.
---
 lisp/ob-tangle-sync.el | 130 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)
 create mode 100644 lisp/ob-tangle-sync.el

diff --git a/lisp/ob-tangle-sync.el b/lisp/ob-tangle-sync.el
new file mode 100644
index 000000000..35513fff2
--- /dev/null
+++ b/lisp/ob-tangle-sync.el
@@ -0,0 +1,130 @@
+;;; ob-tangle-sync.el --- Synchronize Source Code and Org Files -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+;; Author: Mehmet Tekman
+;; Keywords: literate programming, reproducible research
+;; URL: https://orgmode.org
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Synchronize the code between source blocks and raw source-code files.
+
+;;; Code:
+
+(require 'org-macs)
+(org-assert-version)
+
+(require 'org-element)
+
+
+(defgroup org-babel-tangle-sync nil
+  "Options for synchronizing source code and code blocks."
+  :tag "Org Babel Tangle sync"
+  :group 'org-babel-tangle)
+
+;;;###autoload
+(define-minor-mode org-babel-tangle-sync-mode
+  "Global minor mode that synchronizes tangled files after every save."
+  :global t
+  :lighter " o-ts"
+  (if org-babel-tangle-sync-mode
+      ;; TODO: Work out how to add this hook to every buffer
+      (add-hook 'after-save-hook 'org-babel-tangle-sync-synchronize nil t)
+    (remove-hook 'after-save-hook 'org-babel-tangle-sync-synchronize t)))
+
+(defcustom org-babel-tangle-sync-files nil
+  "A list of `org-mode' files.
+When `org-babel-tangle-sync-mode' is enabled only files listed
+here are subject to the org-babel-tangle-sync treatment.  If nil,
+then all org files with tangle headers are considered."
+  :group 'org-babel-tangle-sync
+  :type 'list
+  :package-version '(Org . "9.7")
+  :set (lambda (var val) (set var (mapcar #'expand-file-name val))))
+
+;;;###autoload
+(defun org-babel-tangle-sync-synchronize ()
+  "Synchronize a tangled code block to its source-specific file, or vice versa.
+If the cursor is either within the source file or in destination
+tangled file, perform a desired tangling action.  The tangling
+action by default is to detangle the tangled files' changes back
+to its source block, or to tangle the source block to its tangled
+file.  Actions are one of `skip' (no action), `import' (detangle
+only), `export' (tangle only), and `both' (default, synchronize
+in both directions).  All `org-mode' source blocks and all tangled
+files with comments are considered valid targets, unless
+specified otherwise by `org-babel-tangle-sync-files'."
+  (interactive)
+  (save-excursion
+    (let* ((orgfile-p (string= major-mode "org-mode"))
+           (link (save-excursion
+                   (re-search-backward org-link-bracket-re nil t)
+		   (match-string-no-properties 0)))
+           (tangled-file-p (and link (not orgfile-p)))
+           ;; Message metrics
+           source-file tangle-file action)
+      ;; Tangled File → Source Block
+      (if tangled-file-p
+          ;; Examine the block: Get the source file and the desired tangle-sync action
+          (let* ((parsed-link (with-temp-buffer
+	                        (let ((org-inhibit-startup nil))
+	                          (insert link)
+	                          (org-mode)
+	                          (goto-char (point-min))
+	                          (org-element-link-parser)))))
+
+            (setq source-file (expand-file-name
+                               (org-element-property :path parsed-link))
+                  tangle-file (buffer-file-name (current-buffer)))
+            ;; De-tangle file back to source block if:
+            ;; - member of sync file list (or list is empty)
+            ;; - source file's tangle-sync action isn't "skip" or "export"
+            (if (or (null org-babel-tangle-sync-files)
+                    (member source-file org-babel-tangle-sync-files))
+                (if (file-exists-p source-file)
+                    (setq action (org-babel-detangle-single-block))
+                  (user-error "Source file '%s' does not exist" source-file))))
+
+        ;; Source Block → Tangled File (or Source Block ← Tangled File (via "import"))
+        (when orgfile-p
+          ;; Tangle action of Source file on Block if:
+          ;; - member of sync file list (or list is empty)
+          (if (or (null org-babel-tangle-sync-files)
+                  (member buffer-file-name org-babel-tangle-sync-files))
+
+              (let* ((block-info (org-babel-get-src-block-info 'no-eval))
+                     (src-headers (nth 2 block-info)))
+
+                (setq source-file (buffer-file-name (current-buffer))
+                      tangle-file (cdr (assq :tangle src-headers))
+                      action (cdr (assq :tangle-sync src-headers)))
+
+                (if (file-exists-p tangle-file)
+                    (org-babel-detangle-single-block--from-source)
+                  (call-interactively 'org-babel-tangle)))))
+
+        (unless (string= action "skip")
+          (message "synced %s %s%s"
+                   source-file
+                   (if (string= action "import") "from ←" "to →")
+                   tangle-file))))))
+
+(provide 'ob-tangle-sync)
+
+;;; ob-tangle-sync.el ends here
-- 
2.40.1

From 22ace85fd4d9fdd61b2e92b79152d95cd571f0e9 Mon Sep 17 00:00:00 2001
From: MT <mtekman89@gmail.com>
Date: Tue, 2 May 2023 18:10:07 +0200
Subject: [PATCH 4/6] lisp/ob-tangle.el: Sync aware tangle function with better
 messages

* ob-tangle.el (org-babel-tangle): The tangle function is now aware of
the desired sync action for a given block by parsing the
`:tangle-sync' source block header in the org file.  It populates
three seperate block counters depending on the action of the block as
given: "skip" = `skip', "tangle" = `export' or `both' or `nil', and
"detangle" = `import').
---
 lisp/ob-tangle.el | 60 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 12 deletions(-)

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index 596b4b3eb..cbe6fca0d 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -244,10 +244,13 @@ matching a regular expression."
 	      (goto-char head)
 	    (user-error "Point is not in a source code block"))))
       (let ((block-counter 0)
+            (skip-counter 0)
+            (blocks-to-detangle nil)
 	    (org-babel-default-header-args
 	     (if target-file
 		 (org-babel-merge-params org-babel-default-header-args
-					 (list (cons :tangle target-file)))
+					 (list (cons :tangle target-file)
+                                               (cons :tangle-sync "both")))
 	       org-babel-default-header-args))
 	    (tangle-file
 	     (when (equal arg '(16))
@@ -281,7 +284,10 @@ matching a regular expression."
 			     (get-spec (lambda (name) (cdr (assq name (nth 4 spec)))))
 			     (she-bang (let ((sheb (funcall get-spec :shebang)))
 				         (when (> (length sheb) 0) sheb)))
-			     (tangle-mode (funcall get-spec :tangle-mode)))
+                             (tangle-name (funcall get-spec :tangle))
+			     (tangle-mode (funcall get-spec :tangle-mode))
+                             (tangle-sync (funcall get-spec :tangle-sync))
+                             (tfile-block (nth 8 lspec)))
 		        (unless (string-equal block-lang lang)
 			  (setq lang block-lang)
 			  (let ((lang-f (org-src-get-lang-mode lang)))
@@ -291,6 +297,19 @@ matching a regular expression."
 			  (unless tangle-mode (setq tangle-mode #o755)))
 		        (when tangle-mode
 			  (add-to-list 'modes (org-babel-interpret-file-mode tangle-mode)))
+                        ;; Replace block contents with remote tangle
+                        ;; comments if "import" or "skip".
+                        (when (and tfile-block (or (string= "import" tangle-sync)
+                                                   (string= "skip" tangle-sync)))
+                          (let* ((remote-body (with-current-buffer (find-file-noselect tangle-name)
+                                                (buffer-substring
+                                                 (plist-get tfile-block :start)
+                                                 (plist-get tfile-block :end)))))
+                            ;; Replace the spec text body with the remote body contents
+                            (setf (nth 5 spec) remote-body)
+                            (if (string= "import" tangle-sync)
+                                (push spec blocks-to-detangle)
+                              (setq skip-counter (+ 1 skip-counter)))))
 		        ;; Possibly create the parent directories for file.
 		        (let ((m (funcall get-spec :mkdirp)))
 			  (and m fnd (not (string= m "no"))
@@ -302,8 +321,8 @@ matching a regular expression."
 		        (when (and she-bang (not she-banged))
 			  (insert (concat she-bang "\n"))
 			  (setq she-banged t))
-		        (org-babel-spec-to-string spec)
-		        (setq block-counter (+ 1 block-counter))))
+		        (org-babel-spec-to-string spec))
+		        (setq block-counter (+ 1 block-counter)))
 		    lspecs)
 		   (when make-dir
 		     (make-directory fnd 'parents))
@@ -329,14 +348,31 @@ matching a regular expression."
 	 (if (equal arg '(4))
 	     (org-babel-tangle-single-block 1 t)
 	   (org-babel-tangle-collect-blocks lang-re tangle-file)))
-	(message "Tangled %d code block%s from %s" block-counter
-		 (if (= block-counter 1) "" "s")
-		 (file-name-nondirectory
-		  (buffer-file-name
-		   (or (buffer-base-buffer)
-                       (current-buffer)
-                       (and (org-src-edit-buffer-p)
-                            (org-src-source-buffer))))))
+        (let ((detang-counter (length blocks-to-detangle)))
+          (when (> detang-counter 0)
+            (mapc (lambda (dspec)
+                    (let ((lnum (car dspec))
+                          (new-body (nth 5 dspec)))
+                      ;; For de-tangling, we assume already in the correct source buffer
+                      (goto-char 0)
+                      (forward-line lnum)
+                      (when new-body
+                        (org-babel-update-block-body new-body))))
+                  blocks-to-detangle))
+          (message "Tangled %d code block%s from %s%s%s%s%s" block-counter
+                   (if (= block-counter 1) "" "s")
+                   (file-name-nondirectory
+		    (buffer-file-name
+		     (or (buffer-base-buffer)
+                         (current-buffer)
+                         (and (org-src-edit-buffer-p)
+                              (org-src-source-buffer)))))
+                   (if (= (+ skip-counter detang-counter) 0) "" " of which: ")
+                   (if (= skip-counter 0) ""
+                     (format "%d were skipped" skip-counter))
+                   (if (= (* skip-counter detang-counter) 0) "" " and ")
+                   (if (= detang-counter 0) ""
+                     (format "%d were detangled" detang-counter))))
 	;; run `org-babel-post-tangle-hook' in all tangled files
 	(when org-babel-post-tangle-hook
 	  (mapc
-- 
2.40.1

From b617455d72086086b49cea5ad923e937abe5c0b0 Mon Sep 17 00:00:00 2001
From: MT <mtekman89@gmail.com>
Date: Tue, 2 May 2023 17:50:58 +0200
Subject: [PATCH 2/6] lisp/ob-tangle.el: Sync action-aware detangle function

* ob-tangle.el (org-babel-detangle): The function is now aware of all
source org mode blocks before it detangles the remote contents back to
source.  Depending on the sync action, detangling from a tangled
buffer could instead "skip" the block or "export" (i.e. tangle) the
source org mode block contents to the tangled file.  Each action
returned by `org-babel-detangle-single-block' is then appended to a
counter with produces the appropriate messages for how many blocks
were tangled, detangled, or skipped.

The main idea is that `org-babel-tangle' and `org-babel-detangle' can
exchange information in both directions (source to remote and vice
versa), with the difference being that tangle would typically be
called from the source org-mode file, and that detangle would be
called from the remote tangled file.
---
 lisp/ob-tangle.el | 51 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 16 deletions(-)

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index c6a4d8448..bd9948efe 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -614,13 +614,45 @@ by `org-babel-get-src-block-info'."
 	  (org-fill-template org-babel-tangle-comment-format-end link-data))))
 
 ;; de-tangling functions
-(defun org-babel-detangle (&optional source-code-file)
+(defun org-babel-detangle (&optional arg source-code-file ignore-header)
   "Propagate changes in source file back original to Org file.
 This requires that code blocks were tangled with link comments
-which enable the original code blocks to be found."
-  (interactive)
+which enable the original code blocks to be found.  With one
+universal prefix argument, only detangle the block at point.  If
+IGNORE-HEADER then detangle regardless of `:tangle-sync' status."
+  (interactive "P")
   (save-excursion
     (when source-code-file (find-file source-code-file))
+    (let ((counter 0) (skip-counter 0) (tang-counter 0) end)
+      (cl-letf ((single-block-metrics
+                 (lambda () (let ((action (org-babel-detangle-single-block ignore-header)))
+                         (cond ((string= action "skip")
+                                (setq skip-counter (1+ skip-counter)))
+                               ((string= action "export")
+                                (setq tang-counter (1+ tang-counter))))
+                         (setq counter (1+ counter))))))
+        (if (equal arg '(4))
+            (funcall single-block-metrics)
+          (goto-char (point-min))
+          (while (re-search-forward org-link-bracket-re nil t)
+            (if (and (match-string 2)
+		     (re-search-forward
+		      (concat " " (regexp-quote (match-string 2)) " ends here") nil t))
+	        (progn (setq end (match-end 0))
+		       (forward-line -1)
+                       (funcall single-block-metrics))
+              (setq end (point)))
+            (goto-char end))))
+      (prog1 counter
+        (message "Detangled %d code block%s%s%s%s%s" counter
+                 (if (= counter 1) "" "s")
+                 (if (= (+ skip-counter tang-counter) 0) "" " of which: ")
+                 (if (= skip-counter 0) ""
+                   (format "%d were skipped" skip-counter))
+                 (if (= (* skip-counter tang-counter) 0) "" " and ")
+                 (if (= tang-counter 0) ""
+                   (format "%d were tangled" tang-counter)))))))
+
 
 (defun org-babel-detangle-single-block (&optional action ignore-header)
   "Propagate changes in tangled file with comments back to the
@@ -668,20 +700,7 @@ requesting a data import and ignores the tangle-sync header."
       (org-babel-detangle-single-block))))
 
     (goto-char (point-min))
-    (let ((counter 0) new-body end)
       (while (re-search-forward org-link-bracket-re nil t)
-        (if (and (match-string 2)
-		 (re-search-forward
-		  (concat " " (regexp-quote (match-string 2)) " ends here") nil t))
-	    (progn (setq end (match-end 0))
-		   (forward-line -1)
-		   (save-excursion
-		     (when (setq new-body (org-babel-tangle-jump-to-org))
-		       (org-babel-update-block-body new-body)))
-		   (setq counter (+ 1 counter)))
-	  (setq end (point)))
-        (goto-char end))
-      (prog1 counter (message "Detangled %d code blocks" counter)))))
 
 (defun org-babel-detangle--block-contents (&optional nearest new-body)
   "Get the contents of the current exported block under cursor, or NEAREST if t.
-- 
2.40.1

From 4ef7aec7e30771376f3b4e13e7ce65ab88f358fe Mon Sep 17 00:00:00 2001
From: MT <mtekman89@gmail.com>
Date: Tue, 2 May 2023 18:01:05 +0200
Subject: [PATCH 3/6] lisp/ob-tangle.el: Tangle function made aware of remote
 contents

* ob-tangle (org-babel-tangle--parse-comments): Scans a tangled file
for comment entries and populates an alist of plists containing
information about the remote contents of each block in the tangled
file.
(org-babel-tangle): Before tangling an org mode buffer, the tangle
function pre-populates a list of already tangled blocks in the remote
tangle file using `org-babel-tangle--parse-comments'.  If the desired
tangle-sync action given in the header is to "import" (instead of the
"export"/"both"/nil action), then it retrieves the remote contents and
updates the org mode source block instead, before proceeding down the
buffer to the next block.
---
 lisp/ob-tangle.el | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index bd9948efe..596b4b3eb 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -261,6 +261,16 @@ matching a regular expression."
                (let ((lspecs (cdr by-fn))
 		     (fnd (file-name-directory file-name))
 		     modes make-dir she-banged lang)
+                 (when (file-exists-p file-name)
+                   ;; Get list of comments in tangled file for potential detangling.
+                   (let ((blocks-in-tfile (cdar (org-babel-tangle--parse-comments
+                                                 file-name target-file))))
+                     ;; Append content boundaries to existing lspecs
+                     (mapc (lambda (lsp)
+                             (let* ((fname (nth 3 lsp))
+                                    (pos-plist (cdr (assoc fname blocks-in-tfile))))
+                               (nconc lsp (list pos-plist))))
+                           lspecs)))
 	         ;; drop source-blocks to file
 	         ;; We avoid append-to-file as it does not work with tramp.
 	         (with-temp-buffer
@@ -699,8 +709,37 @@ requesting a data import and ignores the tangle-sync header."
       (search-forward link-text nil t)
       (org-babel-detangle-single-block))))
 
+
+(defun org-babel-tangle--parse-comments (tangled-file &optional source-file)
+  "Scan TANGLED-FILE for comments, optionally only those stemming from SOURCE-FILE.
+Return an alist of tangled filenames and their blocks, along with
+a plist of their positions."
+  (with-current-buffer (find-file-noselect tangled-file)
     (goto-char (point-min))
+    (let ((comment-links nil)
+          (source-file (and source-file
+                            (expand-file-name source-file))))
       (while (re-search-forward org-link-bracket-re nil t)
+        (let* ((file-link (match-string-no-properties 1))
+               (block-name (match-string-no-properties 2))
+               (block-file (expand-file-name
+                            (progn (string-match "\\`file:\\(.+?\\)::" file-link)
+                                   (match-string-no-properties 1 file-link))))
+               (start-block (progn (forward-line 1) (point)))
+               (end-block (progn
+                            (re-search-forward
+	                     (concat " " (regexp-quote block-name) " ends here") nil t)
+                            (forward-line 0) (forward-char -1) (point))))
+          ;; if source file given, restrict scope to just those blocks.
+          (unless (and source-file (not (string= source-file block-file)))
+            (if (assoc block-file comment-links)
+                (push `(,file-link :name ,block-name :start ,start-block :end ,end-block)
+                      (cdr (assoc block-file comment-links)))
+              (push `(,block-file (,file-link :name ,block-name :start ,start-block :end ,end-block))
+                    comment-links)))))
+      comment-links)))
+
+
 
 (defun org-babel-detangle--block-contents (&optional nearest new-body)
   "Get the contents of the current exported block under cursor, or NEAREST if t.
-- 
2.40.1

From 34727abb66a01d2f21df0bc612d3a169b64c9a16 Mon Sep 17 00:00:00 2001
From: MT <mtekman89@gmail.com>
Date: Tue, 2 May 2023 17:24:56 +0200
Subject: [PATCH 1/6] lisp/ob-tangle.el: Detangle a single block

* ob-tangle.el (org-babel-detangle--block-contents,
org-babel-detangle-single-block,
org-babel-detangle-single-block--from-source): Detangling the contents
of a single target tangled block back to the original source org mode
block, in place.

(org-babel-detangle--block-contents): Within the comments block of a
remote tangled file, return its body.  If a NEW-BODY argument is
given, then replace the body.

(org-babel-detangle-single-block): Interactive function to detangle
the body of the remote tangled file back into its org mode source
block.  It is invoked from inside the comments block of the tangled
file, and relies on `org-babel-detangle--block-contents' for copying
contents back to source. The value returned is the action that was
performed on the block, which is one of "import" (remote to source),
"export" (source to remote) or "both" (symmetric).

(org-babel-detangle-single-block--from-source): Produces the same
result as `org-babel-detangle-single-block', but is instead invoked
from inside the org mode source block.  It relies on
`org-babel-detangle-single-block' to do the actual detangling.
---
 lisp/ob-tangle.el | 72 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index 980d4a120..c6a4d8448 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -621,6 +621,52 @@ which enable the original code blocks to be found."
   (interactive)
   (save-excursion
     (when source-code-file (find-file source-code-file))
+
+(defun org-babel-detangle-single-block (&optional action ignore-header)
+  "Propagate changes in tangled file with comments back to the
+original source code block in the Org file, whilst respecting the
+`:tangle-sync' action header, unless ACTION is specified, or
+IGNORE-HEADER is t.  Return the tangle-sync action performed."
+  (interactive)
+  (save-window-excursion
+    (let* ((tang-buff (current-buffer))
+           (new-body (org-babel-tangle-jump-to-org))
+           (block-info (org-babel-get-src-block-info 'no-eval))
+           (sync-action (or action (cdr (assq :tangle-sync (nth 2 block-info))))))
+      (cond ((or ignore-header
+                 (string= sync-action "import")
+                 (string= sync-action "both")
+                 (null sync-action))
+             (org-babel-update-block-body new-body))
+            ((string= sync-action "skip") nil)
+            ((string= sync-action "export")
+             ;; Perform in-place tangling without writing to a new
+             ;; buffer. Clean, but bypasses tangle hooks and other
+             ;; tangle-related functions.
+             (with-current-buffer tang-buff
+               (org-babel-detangle--block-contents nil (nth 1 block-info)))))
+      sync-action)))
+
+(defun org-babel-detangle-single-block--from-source ()
+  "Detangle from Org mode source buffer.
+Propagate the remote changes of a tangled file to the current
+source code block under cursor.  Assumes that the block is
+requesting a data import and ignores the tangle-sync header."
+  (pcase-let*
+      ((spec (cdadar (org-babel-tangle-single-block 1 t)))
+       ;; Adapted from `org-babel-spec-to-string'
+       (`(,start ,file ,link ,source ,info ,_body ,_comment) spec)
+       (tangle-file (cdr (assq :tangle info)))
+       (link-data `(("start-line" . ,(number-to-string start))
+		    ("file" . ,file)
+		    ("link" . ,link)
+		    ("source-name" . ,source)))
+       (link-text (org-fill-template org-babel-tangle-comment-format-beg link-data)))
+    (with-current-buffer (find-file-noselect tangle-file)
+      (goto-char (point-min))
+      (search-forward link-text nil t)
+      (org-babel-detangle-single-block))))
+
     (goto-char (point-min))
     (let ((counter 0) new-body end)
       (while (re-search-forward org-link-bracket-re nil t)
@@ -637,6 +683,32 @@ which enable the original code blocks to be found."
         (goto-char end))
       (prog1 counter (message "Detangled %d code blocks" counter)))))
 
+(defun org-babel-detangle--block-contents (&optional nearest new-body)
+  "Get the contents of the current exported block under cursor, or NEAREST if t.
+If NEW-BODY is given, then update the block contents in place."
+  ;; Adapted body from org-babel-detangle
+  (save-excursion
+    (move-end-of-line 1) ;; for backwards regex to work
+    (let* ((cursor (+ 2 (line-beginning-position)))
+           (block-end nil)
+           (body-end nil)
+           (block-start (progn (re-search-backward org-link-bracket-re nil t)
+                               (line-beginning-position)))
+	   (body-start (line-beginning-position 2))
+	   (block-name (match-string 2)))
+      (when block-start
+	(re-search-forward
+	 (concat " " (regexp-quote block-name)
+		 " ends here")
+	 nil t)
+	(setq body-end (line-beginning-position)
+              block-end (line-end-position)))
+      (when (or nearest (and (>= block-end cursor) (>= cursor block-start)))
+        (if new-body
+            (cl--set-buffer-substring body-start body-end (concat new-body "\n"))
+          (buffer-substring body-start body-end))))))
+
+
 (defun org-babel-tangle-jump-to-org ()
   "Jump from a tangled code file to the related Org mode file."
   (interactive)
-- 
2.40.1

From b7ad4b27155cbc85f7e441943ce6b489f86493b6 Mon Sep 17 00:00:00 2001
From: MT <mtekman89@gmail.com>
Date: Tue, 2 May 2023 18:24:39 +0200
Subject: [PATCH 6/6] etc/ORG-NEWS,lisp/ob-tangle.el: Added news and name

* ORG-NEWS: Mentioned block-specific synchronization via the new
`:tangle-sync' header property, and mentioned the new global
`org-babel-tangle-sync-mode' for automatic synchronization.
* ob-tangle.el: Added name to contributors.
---
 etc/ORG-NEWS      | 30 +++++++++++++++++++++++++++++-
 lisp/ob-tangle.el |  2 +-
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 03894f128..cb7b83450 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -207,11 +207,39 @@ selection.
 TODO state, priority, tags, statistics cookies, and COMMENT keywords
 are allowed in the tree structure.
 
-*** Asynchronous code evaluatation in ~ob-shell~
+*** Asynchronous code evaluation in ~ob-shell~
 
 Running shell blocks with the ~:session~ header freezes Emacs until
 execution completes.  The new ~:async~ header allows users to continue
 editing with Emacs while a ~:session~ block executes.
+*** Added block-specific synchronization directions during tangle/detangle operations
+
+Tangling and detangling actions can be specified at the per-block
+basis depending on whether the org-mode source block header argument
+=:tangle-sync <action>= has an action of:
+
+- =skip= :: do nothing
+
+- =import= :: only pull changes from the target tangled block into the
+              org-mode source block.
+
+- =export= :: only push changes from the target org-mode source block
+              into the tangled block
+
+- =both= (or nil) :: freely synchronize changes of current buffer to
+                     the associated source or target buffer.
+
+
+*** Automatic sync of source blocks and tangled blocks in ~ob-tangle-sync~
+
+Invoking the global minor mode =org-babel-tangle-sync-mode=
+synchronizes contents between the current block of a target tangled
+file and its associated org-mode source file block, respecting the
+desired synchronization direction from the =:tangle-sync= header
+argument. This is invoked via the `org-babel-tangle-sync-synchronize'
+function when called from either the target or source buffer, and is
+bound to the =after-save-hook= hook.
+
 
 ** Miscellaneous
 *** Blank lines after removed objects are not retained during export
diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index cbe6fca0d..f199c77bc 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2009-2023 Free Software Foundation, Inc.
 
-;; Author: Eric Schulte
+;; Authors: Eric Schulte, Mehmet Tekman
 ;; Keywords: literate programming, reproducible research
 ;; URL: https://orgmode.org
 
-- 
2.40.1

Reply via email to