From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Joost Kremers Newsgroups: gmane.emacs.bugs Subject: bug#73775: 30.0.90; vtable: can't handle 0 data rows Date: Wed, 16 Oct 2024 18:19:41 +0200 Message-ID: <86h69cf2aq.fsf@fastmail.fm> References: <87ttdhdymx.fsf@gmail.com> <86jzeduqlp.fsf@gnu.org> <04511bb6-0832-47af-8067-2d44ed790f52@alphapapa.net> <864j5gvah8.fsf@gnu.org> <86jzebj599.fsf@fastmail.fm> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="40447"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Eli Zaretskii , arstoffel@gmail.com, 73775@debbugs.gnu.org To: Adam Porter Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Oct 16 18:21:06 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1t16lk-000AGT-1j for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 16 Oct 2024 18:21:04 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t16lP-0002kA-SC; Wed, 16 Oct 2024 12:20:43 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t16lO-0002k0-Qj for bug-gnu-emacs@gnu.org; Wed, 16 Oct 2024 12:20:42 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1t16lO-0006jg-HD for bug-gnu-emacs@gnu.org; Wed, 16 Oct 2024 12:20:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:References:In-Reply-To:From:To:Subject; bh=lYt2JCYk/z7vN86DgRWwrMG7muMnQLvDmIiTRkhHZ68=; b=vs2S8E7f7K1ngoakoJlRZBBSXMp15x6g5d326jBTAj1+RYxEb9Mbv27L9dd3v+bRka+S395FndEEkr/colSLzMAjmzHq3+fQHpoC/UBlK7n3oVQKNGg90lYZLM3VzkL2hC6Tg+fD0qX/aLuaJ6b717gkpwXnI0lSBNGPiV5FTnjW45pbBHa57V3Ooj+GEvCFaC7vNSmSY57/RJ12ZQmNivAVOGtDNMfjUKqGyCrgrrRgp1yAurCMwGGXVsXhic+qZ6qGxFysf7urkSrQkQjiriiqyApJklRoYlzVmNaxpdl0vdew5fRiiASkPAPQ7gHkSG+B4NP4CjGNGglcpTPJ/g==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1t16lh-0000pT-Rf for bug-gnu-emacs@gnu.org; Wed, 16 Oct 2024 12:21:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Joost Kremers Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 16 Oct 2024 16:21:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 73775 X-GNU-PR-Package: emacs Original-Received: via spool by 73775-submit@debbugs.gnu.org id=B73775.17290956292779 (code B ref 73775); Wed, 16 Oct 2024 16:21:01 +0000 Original-Received: (at 73775) by debbugs.gnu.org; 16 Oct 2024 16:20:29 +0000 Original-Received: from localhost ([127.0.0.1]:60185 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t16l9-0000ik-Sw for submit@debbugs.gnu.org; Wed, 16 Oct 2024 12:20:29 -0400 Original-Received: from fhigh-a8-smtp.messagingengine.com ([103.168.172.159]:55707) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t16l6-0000iM-Gr for 73775@debbugs.gnu.org; Wed, 16 Oct 2024 12:20:26 -0400 Original-Received: from phl-compute-03.internal (phl-compute-03.phl.internal [10.202.2.43]) by mailfhigh.phl.internal (Postfix) with ESMTP id 506251140169; Wed, 16 Oct 2024 12:19:47 -0400 (EDT) Original-Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Wed, 16 Oct 2024 12:19:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fastmail.fm; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1729095587; x=1729181987; bh=lYt2JCYk/z 7vN86DgRWwrMG7muMnQLvDmIiTRkhHZ68=; b=RKotG7EVcPRssj0nVzi4dUr5s5 oDvm1NjNIOqENNk9TEc1f+bQpnsuLvtyRPVaLbdB3WbRH2dATQ17xqk+Ui2A0XhG NtyQuDwIKWi0j0Iau+vBdSeLNHokXseB/u6U134cdTHeB/qy0UMpygyfBYGe3ybl quFl2LPP/t0D9XGoBpfP09cz49PAK2nAEsdBgPEMtJI8YR32Y2g9EfTZ85Gf9a+k BPphR4Syfb6/n519fymflLL/6RsxeyTl5Xnkw9C4bA9Phlkw6F1TJlp1EhQwkDGi /GQWM3WjLtcrsZwAFrUl2aqUwD856PX/iUcoYnWHsThHMYPq6YUkxMVmjYgg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; t=1729095587; x=1729181987; bh=lYt2JCYk/z7vN86DgRWwrMG7muMn QLvDmIiTRkhHZ68=; b=PZxmTSAkV+y6qnli6KxirdTwJR30V7lCmqvPi9NznrCr XiOuAgQCk13h72gFa6vdeQ1/JOQt63tla73xHB/Sc4djjn+l1NxY7B4bvLo+BddN mmJzp7lSj8VPh3YpGTiBi96bVuZhuLJhTFDZgGTuZrxPussVHQd8rxfK+5AipebO BoDNcUvaH71Wb6aZpVIB94QhIsGljqiUWffwuSzrZn9EvaCBY+GArLwV5XrgI3xr 7ROu3n+wOCqCsaTAD9zeCC3NklWG4RxU9CeJrslaICCbN+CwWTQ1SNR8tSGQshUz 9NSq6wwWMNFOgATo2+l4x9Rd7pqfd09Df+VwmD0aFQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrvdegledgleelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhephffvvefujghffffkgggtsehmtderredttdejnecu hfhrohhmpeflohhoshhtucfmrhgvmhgvrhhsuceojhhoohhsthhkrhgvmhgvrhhssehfrg hsthhmrghilhdrfhhmqeenucggtffrrghtthgvrhhnpefgfeeuleevuddtteeggfduuefh tdelvdetudffgffggeetkeektdeliefghfejteenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehjohhoshhtkhhrvghmvghrshesfhgrshhtmhgr ihhlrdhfmhdpnhgspghrtghpthhtohepgedpmhhouggvpehsmhhtphhouhhtpdhrtghpth htohepjeefjeejheesuggvsggsuhhgshdrghhnuhdrohhrghdprhgtphhtthhopegrrhhs thhofhhfvghlsehgmhgrihhlrdgtohhmpdhrtghpthhtohepvghlihiisehgnhhurdhorh hgpdhrtghpthhtoheprggurghmsegrlhhphhgrphgrphgrrdhnvght X-ME-Proxy: Feedback-ID: ie15541ac:Fastmail Original-Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 16 Oct 2024 12:19:45 -0400 (EDT) In-Reply-To: (Adam Porter's message of "Tue, 15 Oct 2024 23:12:08 -0500") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:293680 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Adam, Thanks for looking at this. On Tue, Oct 15 2024, Adam Porter wrote: > Just a few minor suggestions: > > + "Compute the display widths for TABLE. > +CACHE is TABLE's cache data as returned by `vtable--compute-cache'." > + (let ((widths (seq-map-indexed > + (lambda (column index) > + (let ((width > + (or > + ;; Explicit widths. > + (and (vtable-column-width column) > + (vtable--compute-width table > (vtable-column-width column))) > + ;; If the vtable is empty and no explicit wid= th > is given, > + ;; set its width to 0 and deal with it below. > + (if (null cache) > > I may be mistaken (as I haven't examined all of the relevant code), but if > CACHE is nil when this function is called, won't it always be null? If so, > you could check its value once, at first, rather than each time through > this loop. Unfortunately, it has to be checked anew in every iteration, because it determines for each column individually if we need to (temporarily) set its width to 0. It also needs to keep the following `seq-max` from erroring out (due to `seq-map` returning `nil`). > + ;; If there are any zero-width columns, divide the remaining window > + ;; width evenly over them. > + (when (member 0 widths) > + (let* ((combined-width (apply #'+ widths)) > + (n-0cols (length (seq-keep #'zerop widths))) > > You could use SEQ-COUNT here, which would avoid consing a new list. There may even be a better way. If I keep track of the number of zero-width columns in the loop above, I don't even need to count them here. I've implemented that in the updated patch attached to this message. > @@ -484,3 +495,8 @@ vtable--compute-columns > table)) > (setf (elt numerical index) nil))) > (vtable-columns table))) > + ;; Check if any columns have an explicit `align' property. > + (unless recompute > + (dolist (column (vtable-columns table)) > + (if (vtable-column-align column) > + (setf (vtable-column--aligned column) t)))) > > This could be a WHEN instead of a "one-armed IF". :) Yes, sirree! (I don't really agree with the "one-armed if should be when"-stance, but I'd be hard-pressed to say when I prefer "if" and when "when", and it's hardly a hill I want to die on, so I made the change. =F0= =9F=98=86 ) --=20 Joost Kremers Life has its moments --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Allow-empty-vtable.patch >From 319fdd16081962aa0a716c0b861baacf41a0f534 Mon Sep 17 00:00:00 2001 From: Joost Kremers Date: Thu, 30 May 2024 13:28:00 +0200 Subject: [PATCH 1/4] Allow empty vtable * lisp/emacs-lisp/vtable.el (vtable--compute-widths): Set default width for columns that have no explicit width and no data. --- lisp/emacs-lisp/vtable.el | 68 ++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el index d58c6894c16..b4c01cdfe6c 100644 --- a/lisp/emacs-lisp/vtable.el +++ b/lisp/emacs-lisp/vtable.el @@ -850,32 +850,48 @@ vtable--compute-width (error "Invalid spec: %s" spec)))) (defun vtable--compute-widths (table cache) - "Compute the display widths for TABLE." - (seq-into - (seq-map-indexed - (lambda (column index) - (let ((width - (or - ;; Explicit widths. - (and (vtable-column-width column) - (vtable--compute-width table (vtable-column-width column))) - ;; Compute based on the displayed widths of - ;; the data. - (seq-max (seq-map (lambda (elem) - (nth 1 (elt (cdr elem) index))) - cache))))) - ;; Let min-width/max-width specs have their say. - (when-let ((min-width (and (vtable-column-min-width column) - (vtable--compute-width - table (vtable-column-min-width column))))) - (setq width (max width min-width))) - (when-let ((max-width (and (vtable-column-max-width column) - (vtable--compute-width - table (vtable-column-max-width column))))) - (setq width (min width max-width))) - width)) - (vtable-columns table)) - 'vector)) + "Compute the display widths for TABLE. +CACHE is TABLE's cache data as returned by `vtable--compute-cache'." + (let* ((n-0cols 0) ; Count the number of zero-width columns. + (widths (seq-map-indexed + (lambda (column index) + (let ((width + (or + ;; Explicit widths. + (and (vtable-column-width column) + (vtable--compute-width table (vtable-column-width column))) + ;; If the vtable is empty and no explicit width is given, + ;; set its width to 0 and deal with it below. + (when (null cache) + (setq n-0cols (1+ n-0cols)) + 0) + ;; Otherwise, compute based on the displayed widths of the + ;; data. + (seq-max (seq-map (lambda (elem) + (nth 1 (elt (cdr elem) index))) + cache))))) + ;; Let min-width/max-width specs have their say. + (when-let ((min-width (and (vtable-column-min-width column) + (vtable--compute-width + table (vtable-column-min-width column))))) + (setq width (max width min-width))) + (when-let ((max-width (and (vtable-column-max-width column) + (vtable--compute-width + table (vtable-column-max-width column))))) + (setq width (min width max-width))) + width)) + (vtable-columns table)))) + ;; If there are any zero-width columns, divide the remaining window + ;; width evenly over them. + (when (> n-0cols 0) + (let* ((combined-width (apply #'+ widths)) + (default-width (/ (- (window-width nil t) combined-width) n-0cols))) + (setq widths (mapcar (lambda (width) + (if (zerop width) + default-width + width)) + widths)))) + (seq-into widths 'vector))) (defun vtable--compute-cache (table) (seq-map -- 2.47.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-Enable-inserting-new-objects-into-empty-vtable.patch >From 9b0509d0b3a5ae78135c63971d2b99ff0bd07ed5 Mon Sep 17 00:00:00 2001 From: Joost Kremers Date: Thu, 30 May 2024 23:20:00 +0200 Subject: [PATCH 2/4] Enable inserting new objects into empty vtable * lisp/emacs-lisp/vtable.el (vtable-insert-object): If the vtable is empty, add the new object and recreate + redisplay the table. --- lisp/emacs-lisp/vtable.el | 151 +++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el index b4c01cdfe6c..0aa3b4c5e76 100644 --- a/lisp/emacs-lisp/vtable.el +++ b/lisp/emacs-lisp/vtable.el @@ -368,86 +368,89 @@ vtable-insert-object case. This also updates the displayed table." - ;; FIXME: Inserting an object into an empty vtable currently isn't - ;; possible. `nconc' fails silently (twice), and `setcar' on the cache - ;; raises an error. + ;; If the vtable is empty, just add the object and regenerate the + ;; table. (if (null (vtable-objects table)) - (error "[vtable] Cannot insert object into empty vtable")) - ;; First insert into the objects. - (let ((pos (if location - (if (integerp location) - (prog1 - (nthcdr location (vtable-objects table)) - ;; Do not prepend if index is too large: - (setq before nil)) - (or (memq location (vtable-objects table)) - ;; Prepend if `location' is not found and - ;; `before' is non-nil: - (and before (vtable-objects table)))) - ;; If `location' is nil and `before' is non-nil, we - ;; prepend the new object. - (if before (vtable-objects table))))) - (if (or before ; If `before' is non-nil, `pos' should be, as well. - (and pos (integerp location))) - ;; Add the new object before. - (let ((old-object (car pos))) - (setcar pos object) - (setcdr pos (cons old-object (cdr pos)))) - ;; Otherwise, add the object after. - (if pos - ;; Splice the object into the list. - (setcdr pos (cons object (cdr pos))) - ;; Otherwise, append the object. - (nconc (vtable-objects table) (list object))))) - ;; Then adjust the cache and display. - (save-excursion - (vtable-goto-table table) - (let* ((cache (vtable--cache table)) - (inhibit-read-only t) - (keymap (get-text-property (point) 'keymap)) - (ellipsis (if (vtable-ellipsis table) - (propertize (truncate-string-ellipsis) - 'face (vtable-face table)) - "")) - (ellipsis-width (string-pixel-width ellipsis)) - (elem (if location ; This binding mirrors the binding of `pos' above. - (if (integerp location) - (nth location (car cache)) - (or (assq location (car cache)) - (and before (caar cache)))) - (if before (caar cache)))) - (pos (memq elem (car cache))) - (line (cons object (vtable--compute-cached-line table object)))) - (if (or before + (progn + (setf (vtable-objects table) (list object)) + (vtable--recompute-numerical table (vtable--compute-cached-line table object)) + (vtable-goto-table table) + (vtable-revert-command)) + ;; First insert into the objects. + (let ((pos (if location + (if (integerp location) + (prog1 + (nthcdr location (vtable-objects table)) + ;; Do not prepend if index is too large: + (setq before nil)) + (or (memq location (vtable-objects table)) + ;; Prepend if `location' is not found and + ;; `before' is non-nil: + (and before (vtable-objects table)))) + ;; If `location' is nil and `before' is non-nil, we + ;; prepend the new object. + (if before (vtable-objects table))))) + (if (or before ; If `before' is non-nil, `pos' should be, as well. (and pos (integerp location))) - ;; Add the new object before:. - (let ((old-line (car pos))) - (setcar pos line) - (setcdr pos (cons old-line (cdr pos))) - (unless (vtable-goto-object (car elem)) - (vtable-beginning-of-table))) + ;; Add the new object before. + (let ((old-object (car pos))) + (setcar pos object) + (setcdr pos (cons old-object (cdr pos)))) ;; Otherwise, add the object after. (if pos ;; Splice the object into the list. - (progn - (setcdr pos (cons line (cdr pos))) - (if (vtable-goto-object location) - (forward-line 1) ; Insert *after*. - (vtable-end-of-table))) + (setcdr pos (cons object (cdr pos))) ;; Otherwise, append the object. - (setcar cache (nconc (car cache) (list line))) - (vtable-end-of-table))) - (let ((start (point))) - ;; FIXME: We have to adjust colors in lines below this if we - ;; have :row-colors. - (vtable--insert-line table line 0 - (nth 1 cache) (vtable--spacer table) - ellipsis ellipsis-width) - (add-text-properties start (point) (list 'keymap keymap - 'vtable table))) - ;; We may have inserted a non-numerical value into a previously - ;; all-numerical table, so recompute. - (vtable--recompute-numerical table (cdr line))))) + (nconc (vtable-objects table) (list object))))) + ;; Then adjust the cache and display. + (save-excursion + (vtable-goto-table table) + (let* ((cache (vtable--cache table)) + (inhibit-read-only t) + (keymap (get-text-property (point) 'keymap)) + (ellipsis (if (vtable-ellipsis table) + (propertize (truncate-string-ellipsis) + 'face (vtable-face table)) + "")) + (ellipsis-width (string-pixel-width ellipsis)) + (elem (if location ; This binding mirrors the binding of `pos' above. + (if (integerp location) + (nth location (car cache)) + (or (assq location (car cache)) + (and before (caar cache)))) + (if before (caar cache)))) + (pos (memq elem (car cache))) + (line (cons object (vtable--compute-cached-line table object)))) + (if (or before + (and pos (integerp location))) + ;; Add the new object before:. + (let ((old-line (car pos))) + (setcar pos line) + (setcdr pos (cons old-line (cdr pos))) + (unless (vtable-goto-object (car elem)) + (vtable-beginning-of-table))) + ;; Otherwise, add the object after. + (if pos + ;; Splice the object into the list. + (progn + (setcdr pos (cons line (cdr pos))) + (if (vtable-goto-object location) + (forward-line 1) ; Insert *after*. + (vtable-end-of-table))) + ;; Otherwise, append the object. + (setcar cache (nconc (car cache) (list line))) + (vtable-end-of-table))) + (let ((start (point))) + ;; FIXME: We have to adjust colors in lines below this if we + ;; have :row-colors. + (vtable--insert-line table line 0 + (nth 1 cache) (vtable--spacer table) + ellipsis ellipsis-width) + (add-text-properties start (point) (list 'keymap keymap + 'vtable table))) + ;; We may have inserted a non-numerical value into a previously + ;; all-numerical table, so recompute. + (vtable--recompute-numerical table (cdr line)))))) (defun vtable-column (table index) "Return the name of the INDEXth column in TABLE." -- 2.47.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-vtable-allow-resetting-column-alignment-when-table-d.patch >From bfd6dcd2c8052af091824877bf92c3169962ed8c Mon Sep 17 00:00:00 2001 From: Joost Kremers Date: Fri, 31 May 2024 01:38:54 +0200 Subject: [PATCH 3/4] vtable: allow resetting column alignment when table data changes * lisp/emacs-lisp/vtable.el (vtable--compute-columns): if a column was not created with an explicit 'align' property, allow changing this property when the column data changes from numeric to non-numeric (or vice versa). This makes it possible to add data to an empty table, because in a table without data all columns are assumed to be numeric and right-aligned. --- lisp/emacs-lisp/vtable.el | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el index 0aa3b4c5e76..6b6487847b9 100644 --- a/lisp/emacs-lisp/vtable.el +++ b/lisp/emacs-lisp/vtable.el @@ -45,7 +45,8 @@ vtable-column getter formatter displayer - -numerical) + -numerical + -aligned) (defclass vtable () ((columns :initarg :columns :accessor vtable-columns) @@ -473,7 +474,17 @@ vtable--get-value (t (elt object index)))) -(defun vtable--compute-columns (table) +(defun vtable--compute-columns (table &optional recompute) + "Compute column specs for TABLE. +Set the `align', `-aligned' and `-numerical' properties of each column. +If the column contains only numerical data, set `-numerical' to t, +otherwise to nil. `-aligned' indicates whether the column has an +`align' property set by the user. If it does, `align' is not touched, +otherwise it is set to `right' for numeric columns and to `left' for +non-numeric columns. + +If RECOMPUTE is non-nil, do not set `-aligned'. This can be used to +recompute the column specs when the table data has changed." (let ((numerical (make-vector (length (vtable-columns table)) t)) (columns (vtable-columns table))) ;; First determine whether there are any all-numerical columns. @@ -484,11 +495,16 @@ vtable--compute-columns table)) (setf (elt numerical index) nil))) (vtable-columns table))) + ;; Check if any columns have an explicit `align' property. + (unless recompute + (dolist (column (vtable-columns table)) + (when (vtable-column-align column) + (setf (vtable-column--aligned column) t)))) ;; Then fill in defaults. (seq-map-indexed (lambda (column index) ;; This is used when displaying. - (unless (vtable-column-align column) + (unless (vtable-column--aligned column) (setf (vtable-column-align column) (if (elt numerical index) 'right @@ -813,7 +829,7 @@ vtable--recompute-numerical (setq recompute t))) line) (when recompute - (vtable--compute-columns table)))) + (vtable--compute-columns table t)))) (defun vtable--set-header-line (table widths spacer) (setq header-line-format -- 2.47.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-Update-vtable-documentation.patch >From da903db0bcf310376d4ff7aaf3578bb576cfa1b7 Mon Sep 17 00:00:00 2001 From: Joost Kremers Date: Mon, 14 Oct 2024 13:10:57 +0200 Subject: [PATCH 4/4] Update vtable documentation * docs/misc/vtable.texi: Document creation of empty vtables. * etc/NEWS: Announce empty vtables. --- doc/misc/vtable.texi | 11 +++++++++++ etc/NEWS | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi index 795d7fad037..b2ead47d0bc 100644 --- a/doc/misc/vtable.texi +++ b/doc/misc/vtable.texi @@ -264,6 +264,10 @@ Making A Table more elements in the sequence than there is in @code{:columns}, only the @code{:columns} first elements are displayed. +If the @code{:objects} list is empty (and no @code{:objects-function} is +defined), an empty vtable is created. In this case, a @code{:columns} +spec must be provided. + @item :objects-function It's often convenient to generate the objects dynamically (for instance, to make reversion work automatically). In that case, this @@ -295,6 +299,11 @@ Making A Table @var{n} percent of the window's width. @end table +If no @code{width} is provided, the width is calculated based on the +column data (provided in the @code{:objects} list or through the +@code{:objects-function}) or, if there is no data, on the basis of the +window width. + @item min-width This uses the same format as @code{width}, but specifies the minimum width (and overrides @code{width} if @code{width} is smaller than this. @@ -576,6 +585,8 @@ Interface Functions index is too small, or appended if it is too large. In this case, @var{before} is ignored. +If @var{table} is empty, @var{location} and @var{before} are ignored. + This also updates the displayed table. @end defun diff --git a/etc/NEWS b/etc/NEWS index 4346fb4aedd..ecd22499767 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -662,6 +662,15 @@ This lets a Lisp program access the core functionality of the program, choosing the program according to the operating system's conventions. +** 'make-vtable' can create an empty vtable +It is now possible to create a vtable without data, by leaving the +':objects' list empty, or by providing a ':objects-function' that +(initially) produces no data. In such a case, it is necessary to +provide a ':columns' spec, so that the number of columns and their +widths can be determined. Columns widths can be set explicitly, or they +will be calculated based on the window width. + + * Changes in Emacs 31.1 on Non-Free Operating Systems -- 2.47.0 --=-=-=--