From b37382caef07d02128c26bb86c23e70b8b54c306 Mon Sep 17 00:00:00 2001
From: Mingtong Lin <mt.oss@fastmail.com>
Date: Thu, 27 Nov 2025 18:11:51 -0500
Subject: [PATCH 2/6] ob-tangle.el: Fix incorrect trimming behavior on tangled
 blocks

* lisp/ob-tangle.el (org-babel-tangle-single-block): Remove incorrect
`org-trim' calls.

* lisp/ob-emacs-lisp.el (org-babel-expand-body:elisp): Remove the
trailing empty line.

* lisp/ob-java.el (org-babel-expand-body:java): Do not insert a
leading newline before the class declaration when there is no package
or imports above it.

* lisp/ob-sql.el (org-babel-expand-body:sql):
* lisp/ob-sqlite.el (org-babel-expand-body:sqlite): Filter nil
prologue/epilogue from the list before joining, so that absent
prologue/epilogue do not produce spurious leading/trailing newlines.

All the trailing empty lines in tangled blocks are trimmed by
`org-babel-tangle-single-block', which I believe is due to the fix on
trailing empty lines created by org-babel-expand-body:xxx calls.

In fact, it is the org-babel-expand-body:xxx functions that should be
fixed, rather than an overkilling remedy at tangle time.

Before:
,#+begin_src emacs-lisp :tangle xxx.el
"hello"

,#+end_src

tangles to

,#+begin_src emacs-lisp
"hello"
,#+end_src

Now:

,#+begin_src emacs-lisp
"hello"

,#+end_src

* testing/lisp/test-ob-tangle.el: Add test.

Reported-by: "Mingtong Lin" <mt.oss@fastmail.com>
Link: https://list.orgmode.org/f43360bb-dc8f-41bb-b40e-dfdd38ebb87b@app.fastmail.com/
---
 lisp/ob-emacs-lisp.el          |  2 +-
 lisp/ob-java.el                |  3 ++-
 lisp/ob-sql.el                 |  9 ++++-----
 lisp/ob-sqlite.el              |  9 ++++-----
 lisp/ob-tangle.el              |  4 ++--
 testing/lisp/test-ob-tangle.el | 22 ++++++++++++++++++++++
 6 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/lisp/ob-emacs-lisp.el b/lisp/ob-emacs-lisp.el
index 416f86185..cbbb54832 100644
--- a/lisp/ob-emacs-lisp.el
+++ b/lisp/ob-emacs-lisp.el
@@ -51,7 +51,7 @@ by `org-edit-src-code'.")
 	(print-length nil)
         (prologue (cdr (assq :prologue params)))
         (epilogue (cdr (assq :epilogue params))))
-    (if (null vars) (concat body "\n")
+    (if (null vars) body
       (format "(let (%s)\n%s%s%s\n)"
 	      (mapconcat
 	       (lambda (var)
diff --git a/lisp/ob-java.el b/lisp/ob-java.el
index ec0c99b5d..3657ca6dc 100644
--- a/lisp/ob-java.el
+++ b/lisp/ob-java.el
@@ -367,7 +367,8 @@ is simplest to expand the code block from the inside out."
       (when (not (re-search-forward org-babel-java--class-re nil t))
         (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it
         (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them
-        (insert (concat "\npublic class " (file-name-base classname) " {\n"))
+        (unless (bobp) (insert "\n"))
+        (insert (concat "public class " (file-name-base classname) " {\n"))
         (indent-code-rigidly (point) (point-max) 4)
         (goto-char (point-max))
         (insert "\n}"))
diff --git a/lisp/ob-sql.el b/lisp/ob-sql.el
index 1d8234835..3f6fdf553 100644
--- a/lisp/ob-sql.el
+++ b/lisp/ob-sql.el
@@ -101,11 +101,10 @@
   (let ((prologue (cdr (assq :prologue params)))
 	(epilogue (cdr (assq :epilogue params))))
     (mapconcat 'identity
-               (list
-                prologue
-                (org-babel-sql-expand-vars
-                 body (org-babel--get-vars params))
-                epilogue)
+               (delq nil (list prologue
+                               (org-babel-sql-expand-vars
+                                body (org-babel--get-vars params))
+                               epilogue))
                "\n")))
 
 (defun org-babel-edit-prep:sql (info)
diff --git a/lisp/ob-sqlite.el b/lisp/ob-sqlite.el
index 35c0ed9ac..9996180fa 100644
--- a/lisp/ob-sqlite.el
+++ b/lisp/ob-sqlite.el
@@ -60,11 +60,10 @@
   (let ((prologue (cdr (assq :prologue params)))
 	(epilogue (cdr (assq :epilogue params))))
     (mapconcat 'identity
-               (list
-                prologue
-                (org-babel-sql-expand-vars
-                 body (org-babel--get-vars params) t)
-                epilogue)
+               (delq nil (list prologue
+                               (org-babel-sql-expand-vars
+                                body (org-babel--get-vars params) t)
+                               epilogue))
                "\n")))
 
 (defvar org-babel-sqlite3-command "sqlite3")
diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index 6e4ae07da..69e46eee3 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -659,8 +659,8 @@ non-nil, return the full association list to be used by
 		link
 		source-name
 		params
-		(if (org-src-preserve-indentation-p) (org-trim body t)
-		  (org-trim (org-remove-indentation body)))
+		(if (org-src-preserve-indentation-p) body
+		  (org-remove-indentation body))
 		comment)))
     (if only-this-block
         (let* ((file-names (org-babel-tangle--compute-targets file info)))
diff --git a/testing/lisp/test-ob-tangle.el b/testing/lisp/test-ob-tangle.el
index b71c32cb5..a560ed890 100644
--- a/testing/lisp/test-ob-tangle.el
+++ b/testing/lisp/test-ob-tangle.el
@@ -54,6 +54,28 @@
 ;;      (should-not (exp-p "no"))
 ;;      (should (exp-p "tangle"))))))
 
+(ert-deftest ob-tangle/tangle-preserve-trailing-empty-lines ()
+  "Test tangle with trailing empty lines."
+  (should
+   (equal
+    "1
+
+"
+    (org-test-with-temp-text-in-file
+    "
+#+header: :tangle \"test-ob-tangle.el\"
+#+begin_src emacs-lisp
+1
+
+#+end_src"
+    (unwind-protect
+        (progn
+          (org-babel-tangle)
+          (with-temp-buffer
+            (insert-file-contents "test-ob-tangle.el")
+            (buffer-string)))
+      (delete-file "test-ob-tangle.el"))))))
+
 (ert-deftest ob-tangle/no-excessive-id-insertion-on-tangle ()
   "Don't add IDs to headings without tangling code blocks."
   (org-test-at-id "ef06fd7f-012b-4fde-87a2-2ae91504ea7e"
-- 
2.39.5 (Apple Git-154)

