After thinking about this series again, I think the original split into 15 very small commits may make the series harder to review than necessary.
I have prepared a squashed version instead, split into two patches: 1. add and refine the section headings 2. move the existing code under those sections This keeps the distinction between structural changes and code movement, but should make the series easier to review. There should still be no behavior change. Best -- Slawomir Grochowski
>From 33ce75a7239ca91f6c9aeeb4b9c680aee307ef4d Mon Sep 17 00:00:00 2001 From: Slawomir Grochowski <[email protected]> Date: Thu, 14 May 2026 02:48:46 +0200 Subject: [PATCH 1/2] org-colview: Organize code with section headings * lisp/org-colview.el: Add section headings to group related code. Pure code organization. No behavior change. --- lisp/org-colview.el | 53 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/lisp/org-colview.el b/lisp/org-colview.el index 1975202db..a151ea443 100644 --- a/lisp/org-colview.el +++ b/lisp/org-colview.el @@ -28,6 +28,7 @@ ;; This file contains the column view for Org. ;;; Code: +;;;; Require other packages (require 'org-macs) (org-assert-version) @@ -57,7 +58,7 @@ (defvar org-inlinetask-min-level) -;;; Configuration +;;;; Customizable variables (defcustom org-columns-checkbox-allowed-values '("[ ]" "[X]") "Allowed values for columns with SUMMARY-TYPE that uses checkbox. @@ -132,6 +133,8 @@ For more information, see `org-columns-dblock-write-default'." ;;; Column View +;;;; State + (defvar-local org-columns-overlays nil "Holds the list of current column overlays.") (put 'org-columns-overlays 'permanent-local t) @@ -181,6 +184,8 @@ This is the compiled version of the format.") "Map operators to summary functions. See `org-columns-summary-types' for details.") +;;;; Keymap and menu + (defun org-columns-content () "Switch to contents view while in columns view." (interactive nil org-mode) @@ -249,6 +254,8 @@ See `org-columns-summary-types' for details.") "--" ["Quit" org-columns-quit t])) +;;;; Value collection + (defun org-columns--displayed-value (spec value &optional no-star) "Return displayed value for specification SPEC in current entry. @@ -320,6 +327,8 @@ displayed without leading stars." (list spec value (org-columns--displayed-value spec value agenda-mode)))) fmt))) +;;;; Column widths + (defun org-columns--set-widths (cache) "Compute the maximum column widths from the format and CACHE. This function sets `org-columns-current-maxwidths' as a vector of @@ -356,6 +365,10 @@ where: (setq w (cdr w))))) (apply #'vector widths)))) +;;;; Overlay rendering + +;;;;; Overlay helpers + (defun org-columns--new-overlay (beg end &optional string face) "Create a new column overlay and add it to the list." (let ((ov (make-overlay beg end))) @@ -418,6 +431,8 @@ This is needed to later remove this relative remapping.") (defvar org-columns--read-only-string nil) +;;;;; Line rendering + (defun org-columns--pad-line-for-overlays () "Pad current line with spaces, one per column if needed. Kludge: column display modifies the buffer here, which it should not. @@ -531,6 +546,8 @@ DATELINE is non-nil when the face used should be (org-columns--hide-rest-of-line) (org-columns--mark-line-read-only)))) +;;;; Display string formatting + (defun org-columns--truncate-below-width (string width) "Return a substring of STRING no wider than WIDTH. This substring must start at 0, and must be the longest possible @@ -556,6 +573,8 @@ substring whose `string-width' does not exceed WIDTH." string (- width (string-width org-columns-ellipses))) org-columns-ellipses)))) +;;;; Header line + (defvar org-columns-full-header-line-format nil "The full header line format, will be shifted by horizontal scrolling." ) (defvar org-previous-header-line-format nil @@ -574,6 +593,8 @@ for the duration of the command.") (defvar header-line-format) (defvar org-columns-previous-hscroll 0) +;;;; View environment + (defun org-columns--suspend-conflicting-modes () "Suspend minor modes that conflict with column view." (when (setq-local org-columns-flyspell-was-active @@ -640,6 +661,8 @@ Saved value is restored by `org-columns--resume-line-wrapping'." (defvar org-colview-initial-truncate-line-value nil "Remember the value of `truncate-lines' across colview.") +;;;; View lifecycle + ;;;###autoload (defun org-columns-remove-overlays () "Remove all currently active column overlays." @@ -664,6 +687,8 @@ Saved value is restored by `org-columns--resume-line-wrapping'." (org-columns--resume-conflicting-modes) (org-columns--resume-line-wrapping))) +;;;; Cell actions + (defun org-columns-show-value () "Show the full value of the property." (interactive nil org-mode org-agenda-mode) @@ -682,6 +707,8 @@ Saved value is restored by `org-columns--resume-line-wrapping'." (message "Modification not yet reflected in Agenda buffer, use `r' to refresh"))) +;;;; Cell editing and value selection + (defun org-columns-check-computed () "Throw an error if current column value is computed." (let ((spec (nth (org-current-text-column) org-columns-current-fmt-compiled))) @@ -905,6 +932,8 @@ around it." (let ((value (get-char-property (point) 'org-columns-value))) (org-link-open-from-string value arg))) +;;;; Format selection and startup + ;;;###autoload (defun org-columns-get-format-and-top-level () (let ((fmt (org-columns-get-format))) @@ -1016,6 +1045,8 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column format." (if doc (format " -- %s" doc) ""))))))))) (complete-with-action flag completion-table string pred))) +;;;; Column definition editing + (defun org-columns-new (&optional spec &rest attributes) "Insert a new column, to the left of the current column. Interactively fill attributes for new column. When column format @@ -1094,6 +1125,8 @@ non-interactively. See `org-columns-compile-format' for details." (interactive "p" org-mode org-agenda-mode) (org-columns-widen (- arg))) +;;;; Navigation and reordering + (defun org-columns--move-cursor (up) "Move cursor up or down one row. When UP is non-nil, move up; otherwise, move down." @@ -1172,6 +1205,8 @@ With non-nil optional argument UP, move it up." (interactive nil org-mode) (org-columns--move-row 'up)) +;;;; Format storage + (defun org-columns-store-format () "Store the text version of the current columns format. The format is stored either in the COLUMNS property of the node @@ -1202,6 +1237,8 @@ the current buffer." (insert-before-markers "#+COLUMNS: " fmt "\n")))) (setq-local org-columns-default-format fmt)))))) +;;;; Display update + (defun org-columns-update (property) "Recompute PROPERTY, and update the columns display for it." (org-columns-compute property) @@ -1244,6 +1281,8 @@ the current buffer." (call-interactively #'org-agenda-columns))) (message "Recomputing columns...done"))) +;;;; Format compilation + (defun org-columns-uncompile-format (compiled) "Turn the compiled columns format back into a string representation. @@ -1302,6 +1341,8 @@ Set and return `org-columns-current-fmt-compiled'." ;;;; Column View Summary +;;;;; Summary helpers + (defun org-columns--age-to-minutes (s) "Turn age string S into a number of minutes. An age is either computed from a given timestamp, or indicated @@ -1328,6 +1369,8 @@ Return the result as a duration." (apply fun (mapcar #'org-duration-to-minutes times)) (org-duration-h:mm-only-p times))) +;;;;; Tree summary computation + (defun org-columns--compute-spec (spec &optional update) "Update tree according to SPEC. SPEC is a column format specification. When optional argument @@ -1428,6 +1471,8 @@ column specification." (org-columns--compute-spec spec (not (member property seen))) (push property seen))))) +;;;;; Summary operators + (defun org-columns--summary-sum (values fmt) "Compute the sum of VALUES. When FMT is non-nil, use it to format the result." @@ -1534,6 +1579,8 @@ and variances (respectively) of the individual estimates." ;;; Dynamic block for Column view +;;;; Capturing + (defun org-columns--capture-view (maxlevel match skip-empty exclude-tags format local) "Get the column view of the current buffer. @@ -1602,6 +1649,8 @@ an inline src-block." (org-no-properties (org-element-interpret-data data))))) +;;;; Writing + ;;;###autoload (defun org-dblock-write:columnview (params) "Write the column view table. @@ -1778,6 +1827,8 @@ definition." (when (seq-find #'identity width-specs) (org-table-shrink)))))) +;;;; Insertion and registration + ;;;###autoload (defun org-columns-insert-dblock () "Create a dynamic block capturing a column view table." -- 2.39.5
>From 0eacab3187201f1859e1d7d96351eb257b4287ac Mon Sep 17 00:00:00 2001 From: Slawomir Grochowski <[email protected]> Date: Fri, 15 May 2026 10:22:19 +0200 Subject: [PATCH 2/2] org-colview: Group related column view helpers Move helper functions and state variables next to the section headings that describe their role. Pure code organization. No behavior change. --- lisp/org-colview.el | 215 ++++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 109 deletions(-) diff --git a/lisp/org-colview.el b/lisp/org-colview.el index a151ea443..60ad0760c 100644 --- a/lisp/org-colview.el +++ b/lisp/org-colview.el @@ -52,6 +52,7 @@ (declare-function face-remap-add-relative "face-remap" (face &rest specs)) (defvar org-agenda-columns-add-appointments-to-effort-sum) +(defvar org-agenda-columns-active) ;; defined in org-agenda.el (defvar org-agenda-columns-compute-summary-properties) (defvar org-agenda-columns-show-summaries) (defvar org-agenda-view-columns-initially) @@ -385,25 +386,6 @@ non-nil, omit the trailing space after the separator, since no further column follows." (format (if lastp "%%-%d.%ds |" "%%-%d.%ds | ") width width)) -(defun org-columns--summarize (operator) - "Return summary function associated to string OPERATOR." - (pcase (or (assoc operator org-columns-summary-types) - (assoc operator org-columns-summary-types-default)) - (`nil (error "Unknown %S operator" operator)) - (`(,_ . ,(and (pred functionp) summarize)) summarize) - (`(,_ ,summarize ,_) summarize) - (_ (error "Invalid definition for operator %S" operator)))) - -(defun org-columns--collect (operator) - "Return collect function associated to string OPERATOR. -Return nil if no collect function is associated to OPERATOR." - (pcase (or (assoc operator org-columns-summary-types) - (assoc operator org-columns-summary-types-default)) - (`nil (error "Unknown %S operator" operator)) - (`(,_ . ,(pred functionp)) nil) ;default value - (`(,_ ,_ ,collect) collect) - (_ (error "Invalid definition for operator %S" operator)))) - (defun org-columns--overlay-text (value fmt width property original) "Return decorated VALUE string for columns overlay display. FMT is a format string. WIDTH is the width of the column, as an @@ -425,10 +407,6 @@ ORIGINAL is the real string, i.e., before it is modified by ("TODO" (propertize v 'face (org-get-todo-face original))) (_ v))))) -(defvar-local org-columns-header-line-remap nil - "Store the relative remapping of column header-line. -This is needed to later remove this relative remapping.") - (defvar org-columns--read-only-string nil) ;;;;; Line rendering @@ -481,12 +459,6 @@ line-beginning, keeping the rendered overlay region uneditable." "Type \\<org-columns-map>`\\[org-columns-edit-value]' \ to edit property" t))))))) -(defun org-columns--remap-header-line () - "Remap the header line to default face if not already done." - (unless org-columns-header-line-remap - (setq org-columns-header-line-remap - (face-remap-add-relative 'header-line '(:inherit default))))) - (defun org-columns--make-row (columns face) "Create and install the overlay for each column on the next character." (let ((i 0) @@ -573,12 +545,8 @@ substring whose `string-width' does not exceed WIDTH." string (- width (string-width org-columns-ellipses))) org-columns-ellipses)))) -;;;; Header line +;;;; View environment -(defvar org-columns-full-header-line-format nil - "The full header line format, will be shifted by horizontal scrolling." ) -(defvar org-previous-header-line-format nil - "The header line format before column view was turned on.") (defvar org-columns-inhibit-recalculation nil "Inhibit recomputing of columns on column view startup.") (defvar org-columns-flyspell-was-active nil @@ -589,11 +557,8 @@ for the duration of the command.") "Remember the state of `org-num-mode' before column view. Org-num mode can cause problems in columns view, so it is turned off for the duration of the command.") - -(defvar header-line-format) -(defvar org-columns-previous-hscroll 0) - -;;;; View environment +(defvar org-colview-initial-truncate-line-value nil + "Remember the value of `truncate-lines' across colview.") (defun org-columns--suspend-conflicting-modes () "Suspend minor modes that conflict with column view." @@ -624,6 +589,24 @@ Saved value is restored by `org-columns--resume-line-wrapping'." (when (local-variable-p 'org-colview-initial-truncate-line-value) (setq truncate-lines org-colview-initial-truncate-line-value))) +;;;; Header line + +(defvar org-columns-full-header-line-format nil + "The full header line format, will be shifted by horizontal scrolling." ) +(defvar org-previous-header-line-format nil + "The header line format before column view was turned on.") +(defvar header-line-format) +(defvar-local org-columns-header-line-remap nil + "Store the relative remapping of column header-line. +This is needed to later remove this relative remapping.") +(defvar org-columns-previous-hscroll 0) + +(defun org-columns--remap-header-line () + "Remap the header line to default face if not already done." + (unless org-columns-header-line-remap + (setq org-columns-header-line-remap + (face-remap-add-relative 'header-line '(:inherit default))))) + (defun org-columns--display-here-title () "Prepare the table heading with column titles for the window's header line." (let ((title "") @@ -658,9 +641,6 @@ Saved value is restored by `org-columns--resume-line-wrapping'." org-columns-previous-hscroll hscroll) (force-mode-line-update)))) -(defvar org-colview-initial-truncate-line-value nil - "Remember the value of `truncate-lines' across colview.") - ;;;; View lifecycle ;;;###autoload @@ -687,16 +667,6 @@ Saved value is restored by `org-columns--resume-line-wrapping'." (org-columns--resume-conflicting-modes) (org-columns--resume-line-wrapping))) -;;;; Cell actions - -(defun org-columns-show-value () - "Show the full value of the property." - (interactive nil org-mode org-agenda-mode) - (let ((value (get-char-property (point) 'org-columns-value))) - (message "Value is: %s" (or value "")))) - -(defvar org-agenda-columns-active) ;; defined in org-agenda.el - (defun org-columns-quit () "Remove the column overlays and in this way exit column editing." (interactive nil org-mode org-agenda-mode) @@ -707,15 +677,13 @@ Saved value is restored by `org-columns--resume-line-wrapping'." (message "Modification not yet reflected in Agenda buffer, use `r' to refresh"))) -;;;; Cell editing and value selection +;;;; Cell actions -(defun org-columns-check-computed () - "Throw an error if current column value is computed." - (let ((spec (nth (org-current-text-column) org-columns-current-fmt-compiled))) - (and - (nth 3 spec) - (assoc spec (get-text-property (line-beginning-position) 'org-summaries)) - (error "This value is computed from the entry's children")))) +(defun org-columns-show-value () + "Show the full value of the property." + (interactive nil org-mode org-agenda-mode) + (let ((value (get-char-property (point) 'org-columns-value))) + (message "Value is: %s" (or value "")))) (defun org-columns-todo (&optional _arg) "Change the TODO state during column view." @@ -736,17 +704,20 @@ See info documentation about realizing a suitable checkbox." (org-columns-next-allowed-value) t)) -(defvar org-overriding-columns-format nil - "When set, overrides any other format definition for the agenda. -Don't set this, this is meant for dynamic scoping. Set -`org-columns-default-format' and `org-columns-default-format-for-agenda' -instead. You should use this variable only in the local settings -section for a custom agenda view.") +(defun org-columns-open-link (&optional arg) + (interactive "P" org-mode org-agenda-mode) + (let ((value (get-char-property (point) 'org-columns-value))) + (org-link-open-from-string value arg))) -(defvar-local org-local-columns-format nil - "When set, overrides any other format definition for the agenda. -This can be set as a buffer local value to avoid interfering with -dynamic scoping for `org-overriding-columns-format'.") +;;;; Cell editing and value selection + +(defun org-columns-check-computed () + "Throw an error if current column value is computed." + (let ((spec (nth (org-current-text-column) org-columns-current-fmt-compiled))) + (and + (nth 3 spec) + (assoc spec (get-text-property (line-beginning-position) 'org-summaries)) + (error "This value is computed from the entry's children")))) (defun org-columns--execute-and-update (action pom key col) "Execute ACTION and update column view. @@ -927,13 +898,20 @@ around it." (mapcar (lambda (x) (format-time-string fmt (org-encode-time x))) (list time-before time time-after))))) -(defun org-columns-open-link (&optional arg) - (interactive "P" org-mode org-agenda-mode) - (let ((value (get-char-property (point) 'org-columns-value))) - (org-link-open-from-string value arg))) - ;;;; Format selection and startup +(defvar org-overriding-columns-format nil + "When set, overrides any other format definition for the agenda. +Don't set this, this is meant for dynamic scoping. Set +`org-columns-default-format' and `org-columns-default-format-for-agenda' +instead. You should use this variable only in the local settings +section for a custom agenda view.") + +(defvar-local org-local-columns-format nil + "When set, overrides any other format definition for the agenda. +This can be set as a buffer local value to avoid interfering with +dynamic scoping for `org-overriding-columns-format'.") + ;;;###autoload (defun org-columns-get-format-and-top-level () (let ((fmt (org-columns-get-format))) @@ -1022,6 +1000,8 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column format." (goto-char (car entry)) (org-columns--display-here (cdr entry))))))))) +;;;; Column definition editing + (defun org-columns--summary-types-completion-function (string pred flag) (let ((completion-table (org-completion-table-with-metadata @@ -1045,8 +1025,6 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column format." (if doc (format " -- %s" doc) ""))))))))) (complete-with-action flag completion-table string pred))) -;;;; Column definition editing - (defun org-columns-new (&optional spec &rest attributes) "Insert a new column, to the left of the current column. Interactively fill attributes for new column. When column format @@ -1205,38 +1183,6 @@ With non-nil optional argument UP, move it up." (interactive nil org-mode) (org-columns--move-row 'up)) -;;;; Format storage - -(defun org-columns-store-format () - "Store the text version of the current columns format. -The format is stored either in the COLUMNS property of the node -starting the current column display, or in a #+COLUMNS line of -the current buffer." - (let ((fmt (org-columns-uncompile-format org-columns-current-fmt-compiled))) - (setq-local org-columns-current-fmt fmt) - (when org-columns-overlays - (org-with-point-at org-columns-top-level-marker - (if (and (org-at-heading-p) (org-entry-get nil "COLUMNS")) - (org-entry-put nil "COLUMNS" fmt) - (goto-char (point-min)) - (let ((case-fold-search t)) - ;; Try to replace the first COLUMNS keyword available. - (catch :found - (while (re-search-forward "^[ \t]*#\\+COLUMNS:\\(.*\\)" nil t) - (let ((element (save-match-data (org-element-at-point)))) - (when (and (org-element-type-p element 'keyword) - (equal (org-element-property :key element) - "COLUMNS")) - (replace-match (concat " " fmt) t t nil 1) - (throw :found nil)))) - ;; No COLUMNS keyword in the buffer. Insert one at the - ;; beginning, right before the first heading, if any. - (goto-char (point-min)) - (unless (org-at-heading-p) (outline-next-heading)) - (let ((inhibit-read-only t)) - (insert-before-markers "#+COLUMNS: " fmt "\n")))) - (setq-local org-columns-default-format fmt)))))) - ;;;; Display update (defun org-columns-update (property) @@ -1281,6 +1227,38 @@ the current buffer." (call-interactively #'org-agenda-columns))) (message "Recomputing columns...done"))) +;;;; Format storage + +(defun org-columns-store-format () + "Store the text version of the current columns format. +The format is stored either in the COLUMNS property of the node +starting the current column display, or in a #+COLUMNS line of +the current buffer." + (let ((fmt (org-columns-uncompile-format org-columns-current-fmt-compiled))) + (setq-local org-columns-current-fmt fmt) + (when org-columns-overlays + (org-with-point-at org-columns-top-level-marker + (if (and (org-at-heading-p) (org-entry-get nil "COLUMNS")) + (org-entry-put nil "COLUMNS" fmt) + (goto-char (point-min)) + (let ((case-fold-search t)) + ;; Try to replace the first COLUMNS keyword available. + (catch :found + (while (re-search-forward "^[ \t]*#\\+COLUMNS:\\(.*\\)" nil t) + (let ((element (save-match-data (org-element-at-point)))) + (when (and (org-element-type-p element 'keyword) + (equal (org-element-property :key element) + "COLUMNS")) + (replace-match (concat " " fmt) t t nil 1) + (throw :found nil)))) + ;; No COLUMNS keyword in the buffer. Insert one at the + ;; beginning, right before the first heading, if any. + (goto-char (point-min)) + (unless (org-at-heading-p) (outline-next-heading)) + (let ((inhibit-read-only t)) + (insert-before-markers "#+COLUMNS: " fmt "\n")))) + (setq-local org-columns-default-format fmt)))))) + ;;;; Format compilation (defun org-columns-uncompile-format (compiled) @@ -1369,6 +1347,25 @@ Return the result as a duration." (apply fun (mapcar #'org-duration-to-minutes times)) (org-duration-h:mm-only-p times))) +(defun org-columns--summarize (operator) + "Return summary function associated to string OPERATOR." + (pcase (or (assoc operator org-columns-summary-types) + (assoc operator org-columns-summary-types-default)) + (`nil (error "Unknown %S operator" operator)) + (`(,_ . ,(and (pred functionp) summarize)) summarize) + (`(,_ ,summarize ,_) summarize) + (_ (error "Invalid definition for operator %S" operator)))) + +(defun org-columns--collect (operator) + "Return collect function associated to string OPERATOR. +Return nil if no collect function is associated to OPERATOR." + (pcase (or (assoc operator org-columns-summary-types) + (assoc operator org-columns-summary-types-default)) + (`nil (error "Unknown %S operator" operator)) + (`(,_ . ,(pred functionp)) nil) ;default value + (`(,_ ,_ ,collect) collect) + (_ (error "Invalid definition for operator %S" operator)))) + ;;;;; Tree summary computation (defun org-columns--compute-spec (spec &optional update) -- 2.39.5
