aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoost Kremers2024-05-07 11:52:27 +0200
committerEli Zaretskii2024-05-18 11:52:33 +0300
commit4f27d763bbe3312b6039fa59f2874bd8e002d201 (patch)
treec31ffaac0bf29a103e229ee903b003267e52a90c
parent19c983ddedf083f82008472c13dfd08ec94b615f (diff)
downloademacs-4f27d763bbe3312b6039fa59f2874bd8e002d201.tar.gz
emacs-4f27d763bbe3312b6039fa59f2874bd8e002d201.zip
Make 'vtable-insert-object' more versatile
* lisp/emacs-lisp/vtable.el (vtable-insert-object): Rename argument AFTER-OBJECT to LOCATION; allow use of index to refer to the insertion position; add argument BEFORE. (Bug#70664). * etc/NEWS: * doc/misc/vtable.texi (Interface Functions): Document the change. * test/lisp/emacs-lisp/vtable-tests.el (test-vtable-insert-object): New test.
-rw-r--r--doc/misc/vtable.texi18
-rw-r--r--etc/NEWS13
-rw-r--r--lisp/emacs-lisp/vtable.el98
-rw-r--r--test/lisp/emacs-lisp/vtable-tests.el30
4 files changed, 132 insertions, 27 deletions
diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi
index dd5b70cf32f..822b1097cd9 100644
--- a/doc/misc/vtable.texi
+++ b/doc/misc/vtable.texi
@@ -548,10 +548,20 @@ Remove @var{object} from @var{table}. This also updates the displayed
548table. 548table.
549@end defun 549@end defun
550 550
551@defun vtable-insert-object table object &optional after-object 551@defun vtable-insert-object table object &optional location before
552Insert @var{object} into @var{table}. If @var{after-object}, insert 552Insert @var{object} into @var{table}. @var{location} should be an
553the object after this object; otherwise append to @var{table}. This 553object in the table, the new object is inserted after this object, or
554also updates the displayed table. 554before it if @var{before} is non-nil. If @var{location} is @code{nil},
555@var{object} is appended to @var{table}, or prepended if @var{before} is
556non-@code{nil}.
557
558@var{location} can also be an integer, a zero-based index into the
559table. In this case, @var{object} is inserted at that index. If the
560index is out of range, @var{object} is prepended to @var{table} if the
561index is too small, or appended if it is too large. In this case,
562@var{before} is ignored.
563
564This also updates the displayed table.
555@end defun 565@end defun
556 566
557@defun vtable-update-object table object &optional old-object 567@defun vtable-update-object table object &optional old-object
diff --git a/etc/NEWS b/etc/NEWS
index 77b2749fe43..5bf9a2d07c8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2635,6 +2635,19 @@ this case, would mean repeating the object in the argument list.) When
2635replacing an object with a different one, passing both the new and old 2635replacing an object with a different one, passing both the new and old
2636objects is still necessary. 2636objects is still necessary.
2637 2637
2638** 'vtable-insert-object' can insert "before" or at an index.
2639The signature of 'vtable-insert-object' has changed and is now:
2640
2641(vtable-insert-object table object &optional location before)
2642
2643'location' corresponds to the old 'after-object' argument; if 'before'
2644is non-nil, the new object is inserted before the 'location' object,
2645making it possible to insert a new object at the top of the
2646table. (Before, this was not possible.) In addition, 'location' can be
2647an integer, a (zero-based) index into the table at which the new object
2648is inserted ('before' is ignored in this case).
2649
2650
2638** JSON 2651** JSON
2639 2652
2640--- 2653---
diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el
index d8e5136c666..cb7ea397314 100644
--- a/lisp/emacs-lisp/vtable.el
+++ b/lisp/emacs-lisp/vtable.el
@@ -348,19 +348,57 @@ This will also remove the displayed line."
348 (when (vtable-goto-object object) 348 (when (vtable-goto-object object)
349 (delete-line))))) 349 (delete-line)))))
350 350
351(defun vtable-insert-object (table object &optional after-object) 351;; FIXME: The fact that the `location' argument of
352 "Insert OBJECT into TABLE after AFTER-OBJECT. 352;; `vtable-insert-object' can be an integer and is then interpreted as
353If AFTER-OBJECT is nil (or doesn't exist in the table), insert 353;; an index precludes the use of integers as objects. This seems a very
354OBJECT at the end. 354;; unlikely use-case, so let's just accept this limitation.
355
356(defun vtable-insert-object (table object &optional location before)
357 "Insert OBJECT into TABLE at LOCATION.
358LOCATION is an object in TABLE. OBJECT is inserted after LOCATION,
359unless BEFORE is non-nil, in which case it is inserted before LOCATION.
360
361If LOCATION is nil, or does not exist in the table, OBJECT is inserted
362at the end of the table, or at the beginning if BEFORE is non-nil.
363
364LOCATION can also be an integer, a (zero-based) index into the table.
365OBJECT is inserted at this location. If the index is out of range,
366OBJECT is inserted at the beginning (if the index is less than 0) or
367end (if the index is too large) of the table. BEFORE is ignored in this
368case.
369
355This also updates the displayed table." 370This also updates the displayed table."
371 ;; FIXME: Inserting an object into an empty vtable currently isn't
372 ;; possible. `nconc' fails silently (twice), and `setcar' on the cache
373 ;; raises an error.
374 (if (null (vtable-objects table))
375 (error "[vtable] Cannot insert object into empty vtable"))
356 ;; First insert into the objects. 376 ;; First insert into the objects.
357 (let (pos) 377 (let ((pos (if location
358 (if (and after-object 378 (if (integerp location)
359 (setq pos (memq after-object (vtable-objects table)))) 379 (prog1
360 ;; Splice into list. 380 (nthcdr location (vtable-objects table))
361 (setcdr pos (cons object (cdr pos))) 381 ;; Do not prepend if index is too large:
362 ;; Append. 382 (setq before nil))
363 (nconc (vtable-objects table) (list object)))) 383 (or (memq location (vtable-objects table))
384 ;; Prepend if `location' is not found and
385 ;; `before' is non-nil:
386 (and before (vtable-objects table))))
387 ;; If `location' is nil and `before' is non-nil, we
388 ;; prepend the new object.
389 (if before (vtable-objects table)))))
390 (if (or before ; If `before' is non-nil, `pos' should be, as well.
391 (and pos (integerp location)))
392 ;; Add the new object before.
393 (let ((old-object (car pos)))
394 (setcar pos object)
395 (setcdr pos (cons old-object (cdr pos))))
396 ;; Otherwise, add the object after.
397 (if pos
398 ;; Splice the object into the list.
399 (setcdr pos (cons object (cdr pos)))
400 ;; Otherwise, append the object.
401 (nconc (vtable-objects table) (list object)))))
364 ;; Then adjust the cache and display. 402 ;; Then adjust the cache and display.
365 (save-excursion 403 (save-excursion
366 (vtable-goto-table table) 404 (vtable-goto-table table)
@@ -372,19 +410,33 @@ This also updates the displayed table."
372 'face (vtable-face table)) 410 'face (vtable-face table))
373 "")) 411 ""))
374 (ellipsis-width (string-pixel-width ellipsis)) 412 (ellipsis-width (string-pixel-width ellipsis))
375 (elem (and after-object 413 (elem (if location ; This binding mirrors the binding of `pos' above.
376 (assq after-object (car cache)))) 414 (if (integerp location)
415 (nth location (car cache))
416 (or (assq location (car cache))
417 (and before (caar cache))))
418 (if before (caar cache))))
419 (pos (memq elem (car cache)))
377 (line (cons object (vtable--compute-cached-line table object)))) 420 (line (cons object (vtable--compute-cached-line table object))))
378 (if (not elem) 421 (if (or before
379 ;; Append. 422 (and pos (integerp location)))
380 (progn 423 ;; Add the new object before:.
381 (setcar cache (nconc (car cache) (list line))) 424 (let ((old-line (car pos)))
382 (vtable-end-of-table)) 425 (setcar pos line)
383 ;; Splice into list. 426 (setcdr pos (cons old-line (cdr pos)))
384 (let ((pos (memq elem (car cache)))) 427 (unless (vtable-goto-object (car elem))
385 (setcdr pos (cons line (cdr pos))) 428 (vtable-beginning-of-table)))
386 (unless (vtable-goto-object after-object) 429 ;; Otherwise, add the object after.
387 (vtable-end-of-table)))) 430 (if pos
431 ;; Splice the object into the list.
432 (progn
433 (setcdr pos (cons line (cdr pos)))
434 (if (vtable-goto-object location)
435 (forward-line 1) ; Insert *after*.
436 (vtable-end-of-table)))
437 ;; Otherwise, append the object.
438 (setcar cache (nconc (car cache) (list line)))
439 (vtable-end-of-table)))
388 (let ((start (point))) 440 (let ((start (point)))
389 ;; FIXME: We have to adjust colors in lines below this if we 441 ;; FIXME: We have to adjust colors in lines below this if we
390 ;; have :row-colors. 442 ;; have :row-colors.
diff --git a/test/lisp/emacs-lisp/vtable-tests.el b/test/lisp/emacs-lisp/vtable-tests.el
index 08fdf1594a4..1d4b0650210 100644
--- a/test/lisp/emacs-lisp/vtable-tests.el
+++ b/test/lisp/emacs-lisp/vtable-tests.el
@@ -39,4 +39,34 @@
39 :insert nil))) 39 :insert nil)))
40 '(left right left)))) 40 '(left right left))))
41 41
42(ert-deftest test-vtable-insert-object ()
43 (should
44 (equal (let ((buffer (get-buffer-create " *vtable-test*")))
45 (pop-to-buffer buffer)
46 (erase-buffer)
47 (let* ((object1 '("Foo" 3))
48 (object2 '("Gazonk" 8))
49 (table (make-vtable
50 :columns '("Name" (:name "Rank" :width 5))
51 :objects (list object1 object2))))
52 (mapc (lambda (args)
53 (pcase-let ((`(,object ,location ,before) args))
54 (vtable-insert-object table object location before)))
55 `( ; Some correct inputs.
56 ;; object location before
57 (("Fizz" 4) ,object1 nil)
58 (("Bop" 7) ,object2 t)
59 (("Zat" 5) 2 nil)
60 (("Dib" 6) 3 t)
61 (("Wup" 9) nil nil)
62 (("Quam" 2) nil t)
63 ;; And some faulty inputs.
64 (("Yat" 1) -1 nil) ; non-existing index, `before' is ignored.
65 (("Vop" 10) 100 t) ; non-existing index, `before' is ignored.
66 (("Jib" 11) ("Bleh" 0) nil) ; non-existing object.
67 (("Nix" 0) ("Ugh" 0) t) ; non-existing object.
68 ))
69 (mapcar #'cadr (vtable-objects table))))
70 (number-sequence 0 11))))
71
42;;; vtable-tests.el ends here 72;;; vtable-tests.el ends here