Hi Jacob,                                                                       
                                                                

Thank you for reporting the issue. I've confirmed it and attached a
patch which addresses the problem. The "$" operator was initially
expanded to its summary function (=org-columns--summary-currencies',
hardcoded to "%.2f") only for parent headings, but the format string
was missing from the spec for subheadings, leading them to display raw
values.

In the process of resolving this, I also refactored
=org-columns-compile-format' for improved readability. This update is
already reflected in the main branch.

The patch ensures that the "$" symbol is normalized during
compilation, which means the implicit "%.2f" format is consistently
applied to subheadings. It also ensures that "$;FMT" is ignored,
aligning with the manual's definition of "Currency, short for +;%.2f"
and the behavior of the existing summary function.

I've included a regression test
(=test-org-colview/columns-currency-shorthand') to cover various
scenarios such as compile, uncompile, single-heading display, and the
two dynamic block scenarios you mentioned.

Please review the attached patch. If everything looks good on your
end, let me know, and I'll proceed with merging it.

Best,
-- 
Slawomir Grochowski

>From 34a107e467608bcfca12e0f6a592788df6c489cf Mon Sep 17 00:00:00 2001
From: Slawomir Grochowski <[email protected]>
Date: Sat, 9 May 2026 09:29:15 +0200
Subject: [PATCH] org-colview.el: Fix inconsistent formatting of the currency
 "$" column summary
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lisp/org-colview.el (org-columns-compile-format): When the
operator is "$", force the spec's format string to "%.2f" and
ignore any user-supplied ";FMT" suffix.  Subheading values now
match the "%.2f" that `org-columns--summary-currencies' hardcodes
for the parent heading summary, and the manual's definition of
"$" as a fixed shorthand for "+;%.2f".
(org-columns-uncompile-format): Mirror the normalization — any "$"
spec serializes back to bare "{$}".
* testing/lisp/test-org-colview.el
(test-org-colview/columns-currency-shorthand): New ert-deftest
gathering compile, uncompile, subheading-display and dynamic-block
assertions for "$" in one place; the contract is summarized as a
comment table above the deftest.  The two dblock cases mirror the
reproductions from the bug report verbatim (single standalone
heading and parent + subheadings).

Reported-by: Jacob S. Gordon <[email protected]>
Link: https://list.orgmode.org/[email protected]/T/#u
---
 lisp/org-colview.el              |  4 +-
 testing/lisp/test-org-colview.el | 81 ++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/lisp/org-colview.el b/lisp/org-colview.el
index b1975ad67..26a87302b 100644
--- a/lisp/org-colview.el
+++ b/lisp/org-colview.el
@@ -1223,6 +1223,7 @@ COMPILED is an alist, as returned by `org-columns-compile-format'."
 		prop
 		(and title (not (equal prop title)) (format "(%s)" title))
 		(cond ((not op) nil)
+		      ((equal op "$") (format "{%s}" op))
 		      (fmt (format "{%s;%s}" op fmt))
 		      (t (format "{%s}" op)))))))
    compiled " "))
@@ -1260,7 +1261,8 @@ Set and return `org-columns-current-fmt-compiled'."
                 (operator (org-string-nw-p (match-string-no-properties 4 fmt))))
            (if operator
                (seq-let (operator format-string) (split-string operator ";")
-                 (list (upcase prop) title width operator format-string))
+                 (list (upcase prop) title width operator
+                       (if (equal operator "$") "%.2f" format-string)))
              (list (upcase prop) title width nil nil))))))
 

diff --git a/testing/lisp/test-org-colview.el b/testing/lisp/test-org-colview.el
index 23a5063a2..41d167440 100644
--- a/testing/lisp/test-org-colview.el
+++ b/testing/lisp/test-org-colview.el
@@ -101,6 +101,87 @@
           (org-columns-compile-format
            "%ITEM(){X}"))))
 
+;; "$" currency shorthand — full contract pinned by the test below.
+;;
+;;   compile     "%COST{$}"      -> ("COST" "COST" nil "$" "%.2f")
+;;   compile     "%COST{$;%.3f}" -> ("COST" "COST" nil "$" "%.2f")  ; ;FMT ignored
+;;   uncompile   ("$" "%.2f")    -> "%COST{$}"
+;;   uncompile   ("$" "%.3f")    -> "%COST{$}"                      ; FMT dropped
+;;   leaf value  "3.5"           -> displayed "3.50"
+;;   dblock leaf-only            -> single row formatted "3.50"
+;;   dblock parent + children    -> parent summary and child leaves all "%.2f"
+(ert-deftest test-org-colview/columns-currency-shorthand ()
+  "Test the \"$\" currency shorthand for `+;%.2f'.
+
+Reported in
+https://list.orgmode.org/[email protected]/T/#u.";
+  ;; compile: "{$}" expands to the canonical ("$" "%.2f")
+  (should
+   (equal '(("COST" "COST" nil "$" "%.2f"))
+          (org-columns-compile-format "%COST{$}")))
+  ;; compile: a user-supplied ";FMT" on "$" is ignored
+  (should
+   (equal '(("COST" "COST" nil "$" "%.2f"))
+          (org-columns-compile-format "%COST{$;%.3f}")))
+  ;; uncompile: any "$" spec serializes back to bare "{$}"
+  (should
+   (equal "%COST{$}"
+          (org-columns-uncompile-format `(("COST" "COST" nil "$" "%.2f")))))
+  (should
+   (equal "%COST{$}"
+          (org-columns-uncompile-format `(("COST" "COST" nil "$" "%.3f")))))
+  ;; leaf values get "%.2f" too, not just summarized parents
+  (should
+   (equal "3.50"
+          (org-test-with-temp-text
+              "* H
+:PROPERTIES:
+:A: 3.5
+:END:"
+            (let ((org-columns-default-format "%A{$}")) (org-columns))
+            (org-trim (get-char-property (point) 'org-columns-value-modified)))))
+  ;; dblock: single leaf headline — value formatted as "%.2f"
+  (should
+   (equal
+    "#+BEGIN: columnview :id global :format \"%ITEM(Item) %COST(Cost){$}\"
+| Item   | Cost |
+|--------+------|
+| Item 1 | 3.50 |
+#+END:"
+    (org-test-with-temp-text
+        "* Item 1
+:PROPERTIES:
+:COST: 3.5
+:END:
+<point>#+BEGIN: columnview :id global :format \"%ITEM(Item) %COST(Cost){$}\"
+#+END:"
+      (org-update-dblock)
+      (buffer-substring-no-properties (point) (point-max)))))
+  ;; dblock: parent + children — parent summary AND child leaves formatted
+  (should
+   (equal
+    "#+BEGIN: columnview :id global :format \"%ITEM(Item) %COST(Cost){$}\"
+| Item   | Cost |
+|--------+------|
+| Item 1 | 3.50 |
+| Item 2 | 2.00 |
+| Item 3 | 1.50 |
+#+END:"
+    (org-test-with-temp-text
+        "* Item 1
+** Item 2
+:PROPERTIES:
+:COST: 2
+:END:
+** Item 3
+:PROPERTIES:
+:COST: 1.5
+:END:
+<point>#+BEGIN: columnview :id global :format \"%ITEM(Item) %COST(Cost){$}\"
+#+END:"
+      (org-update-dblock)
+      (buffer-substring-no-properties (point) (point-max))))))
+
 (ert-deftest test-org-colview/substring-below-width ()
   "Test `org-columns--truncate-below-width'."
   (cl-flet ((check (string width expect)
-- 
2.39.5

Reply via email to