How can I see list of labels?

If I understood well, if you do not use preview-ref, you see that it works. Pls. let me know if I understood well. This is what I saw in my installation of TeXmacs. The reason I think is that preview-ref deletes the balloon widget with the labels before showing the preview.
For the selection possibility you have to use the enum widget which should be accessible through the context menu.
Please let me know if this is working. A piece of code there (the one that finds and indexes duplicate labels) may be slow when there are many labels, but I think I found the way of making it quicker.
Indexing duplicate labels is pretty helpful in that widget because the enum widget by itself filters out of its list all duplicates (keeps only unique entries).

Yes, it works if I switch off preview-ref. But I do not understand about enum widget. How could I switch on it?

You can open the enum widget through the context menu. Right click when in a reference or label field, and at the bottom of the menu you should see the entry “Show labels” (I do not recall precisely the name). Select that and you get the widget, which you can use to insert labels.
Duplicated labels are displayed with an index (starting from (2), and which is not inserted in the document when clicking on the label). Maybe (I did not test it) this widget is slow at appearing when one has many labels, but I think I know how to make it faster.

For making the balloon label compatible with preview-ref I need to learn and think more.

Yes, I know about this, but I did not know that it enum widget :slight_smile: . Thank you once more.

Here you are the code with a better implementation of indexing repeating entries.
Now I do not expect anymore that it can become slow.
It needs more extensive and “strategically” better comments, but commenting it will take time.



;;=============================
;;Label list widget and balloon
;;=============================


;;; Code for indexing repeated entries

;; 1) Mark entries with their list index (use a pair to mark, car is the entry,
;; cdr is the index); will use indices to bring the list back to the original
;; order at the end of the code
;; 2) Partition list of entries into lists of equal entries (do it on the
;; marked list, using only the entries for partitioning)
;; 3) Add indices inside the string of each entry in each group of repeated
;; entries (generate indices using the iota form, append them to entries using
;; mapping)
;; 4) Use index marks to bring the list back to the original ordering

;;; Partitioning
;;; The functions partition, null-list? and check-arg are copied from srfi-1
;; https://srfi.schemers.org/srfi-1/
;; https://github.com/scheme-requests-for-implementation/srfi-1

(define (partition pred lis)
  (check-arg procedure? pred partition)
  (let recur ((lis lis))
       (if (null-list? lis) (values lis lis) ; Use NOT-PAIR? to handle dotted lists.
           (let ((elt (car lis))
		 (tail (cdr lis)))
             (receive (in out) (recur tail)
               (if (pred elt)
                   (values (if (pair? out) (cons elt in) lis) out)
                   (values in (if (pair? in) (cons elt out) lis))))))))

(define (null-list? l)
  (cond ((pair? l) #f)
        ((null? l) #t)
        (else (error "null-list?: argument out of domain" l))))

;; check-arg is in the introductory comments to the srfi-1 code (because it is not part of rsr4)
;; and is needed in the Guile used by TeXmacs 1.99.18
   (define (check-arg pred val caller)
      (let lp ((val val))
        (if (pred val) val (lp (error "Bad argument" val pred caller)))))


;;; Indexed partitioning

;; partitions a list according to pred, then conses one partition to the list
;; equivalence-classes and passes the new list equivalence-classes and the
;; other partition to a copy of itself (recursively).

;; 2021-01-25: I think it works well as long as pred is an equivalence relation
;; (if it is not, the output is not equivalence classes, and it might depend on
;; the order of the input list; I did not investigate this further)
(define (partition-equivalence-classes-aux pred equivalence-classes lst)
  (cond ((null? lst) equivalence-classes) ; base case
	(values
	  (call-with-values
	      (lambda ()
		(partition (lambda (x) (pred (car lst) x)) lst))
	    (lambda (l1 l2)
	      (partition-equivalence-classes-aux
	       pred
	       (cons l1 equivalence-classes)
	       l2))))))

(define (partition-equivalence-classes pred lst)
  (partition-equivalence-classes-aux pred '() lst))

;; marks each element of lst with its position index, then partitions the new
;; list in equivalence classes using equivalence of the car as predicate.
;; In this way, we have a partitioned list and we know which position each
;; element had in the original list
(define (partition-equivalence-classes-indexed pred lst)
  (let ((lst-indexed (map (lambda (x y) (cons x y))
			  lst (iota (length lst)))))
    (partition-equivalence-classes
     (lambda (x y) (pred (car x) (car y)))
     lst-indexed)))

;;; index elements of a list of strings starting from the second element,
;;; adding the index at the end of the string

;; Generate a list of indices, turn them into strings, append them to the
;; strings in the list using map.

;; In the previous version of the code it was done applying the function
;; index-pairs-aux recursively


(define (parenthesize-index n)
   (string-join `("(" ,(number->string n) ")") ""))

(define (string-indices lst)
  (cons "" (map parenthesize-index
		(map (cut + <> 2) (iota (- (length lst) 1))))))

(define (index-element elem index-string)
  (cons (string-join `(,(car elem) ,index-string)) (cdr elem)))

(define (index-pairs-from-second lst)
  (map index-element lst (string-indices lst)))



;; The list of indexed strings is organized into equivalence classes; we
;; flatten it before re-ordering it according to the original ordering (saved
;; in the indices in the cdr). Here is the flattening function
(define (flatten lst)
  (cond ((null? lst) lst)
	((not (list? (car lst))) (cons (car lst) (flatten (cdr lst))))
	(else (append (car lst) (flatten (cdr lst))))))



;;; Tree search

(define (biblio-context? t)
  (or (tree-func? t 'bibliography 4)
      (tree-func? t 'bibliography* 5)))

(tm-define (in-biblio-context? t) (tree-search-upwards t biblio-context?))

;; definition of tree-search
;; in progs/kernel/library/tree.scm

;; (define-public (tree-search t pred?)
;;   (with me (if (pred? t) (list t) '())
;;     (if (tree-atomic? t) me
;; 	(append me (append-map (cut tree-search <> pred?)
;; 			       (tree-children t))))))


;; Starting from the standard tree-search, a tree-search function that does not
;; look inside the current focus.
;; If I find the path of (focus-tree) I exit from the function

;; I could write a single search function that does not look inside the current
;; focus and apply it to every case (since we are looking for labels, excluding
;; the current focus in a reference will find all labels)
(define (tree-search-elsewhere t pred?)
  (with me (if (and (pred? t) ) (list t) '())
    (cond
      ((tree-atomic? t) me)
      ((equal? (tree->path (focus-tree)) (tree->path t)) '())
      (else (append me (append-map (cut tree-search-elsewhere <> pred?)
				   (tree-children t)))))))

(tm-define (search-doc-all-labels t)
  (:synopsis "A function that finds all labels that are not part of the bibliography.")
  (tree-search t
    (lambda (s) (and (label-context? s) (not (in-biblio-context? s)))
	    )))

(tm-define (search-doc-elsewhere-labels t)
  (:synopsis "A function that finds all labels outside the current focus that are not part of the
bibliography.")
  (tree-search-elsewhere t
    (lambda (s) (and (label-context? s) (not (in-biblio-context? s)))
	    )))

(tm-define (search-doc-labels t)
  (if (label-context? (focus-tree))
      (search-doc-elsewhere-labels t)
      (search-doc-all-labels t)))


;;; Filter labels that start as the text typed in the label or reference in focus

(tm-define (filter-labels labels str)
  (:synopsis "Keeps the labels whose start is equal to str")
  (filter (lambda (s)
	    (and (>= (string-length s) (string-length str))
		 (string-contains s str 0 (string-length str)))) 
	  labels))
;; first we check if the string is at least as long as the text in the ref or
;; label (arguments of and are evaluated only up to the first that is false)
;; then we check that the label contains the already-typed text (which is now
;; at most as long as the label).
;; The two indices 0 and (string-length str) cause the comparison to be made
;; only to the beginning substring of s of length equal to the length of str.
;; I think that the indices of string-contains behave like the indices of
;; substring (first included, last excluded), I tested this in one case only:
;; (string-contains "test " "test" 0 4) $0
;; (string-contains "test " "test" 0 3) $#f



;;; Index repeated labels to distinguish them

;; The "enum" widget provided by TeXmacs filters the list to keep only unique
;; entries. We want to see all labels, so we add an index to repeated entries
;; applying the function index-repeated-entries, which needs the function
;; order-indexed-list to put its elements in the original order after it marked
;; them


;; order-indexed-list puts the element marked with i at the i-th place in the
;; output list; for this, it uses imperative code
(define (order-indexed-list lst)
  (let ((ordered-lst (make-list (length lst))))
    (begin
      (do ((i 0 (1+ i))) ((>= i (length lst)))
	(list-set! ordered-lst
		   (cdr (list-ref lst i))
		   (car (list-ref lst i))))
      ordered-lst)))

(define (index-repeated-entries lst)
  (order-indexed-list
   (flatten (map index-pairs-from-second
		 (partition-equivalence-classes-indexed equal? lst)))))



;;; Build label list

;; use search-doc-labels function instead of the standard search-labels, that
;; finds the labels defined in the bibliography as well.
;; The search-doc-labels function behaves differently if in a label (excludes
;; the current focus)
(define (label-list)
  (let ((ls (search-doc-labels (buffer-tree))))
    (map (lambda (l) (tree->string (tm-ref l 0))) ls)))


;;; Widget

;; An insert function that inserts a string only up to before the last blank
(define (keep-till-first-blank str)
  ;; (display "keep-till-first-blank\n")
  (let* ((ind-first-blank (string-index str #\space)))
    ;; if we did not find a blank,
    ;; ind-first-blank is false: keep the
    ;; whole string
    (if ind-first-blank
	(substring str 0 ind-first-blank)
	str)))

(tm-widget (enum-labels)
  (enum (with-cursor ; place the selected item at the end of the current focus
	    (path-end (root-tree) (tree->path (focus-tree)))
	  (insert (keep-till-first-blank answer)))
(index-repeated-entries (label-list)) "Choose label ..."
"24em"))


;;; Balloon

(tm-define (label-balloon)
  (let* ((focus-string (cadr (tree->stree (focus-tree))))
         (ll (filter-labels ; keep only labels that start with the text in focus tree
	      (label-list)
	      focus-string)))
    (display-balloon (cursor-tree) `(document ,@ll) "auto" "auto" "keyboard")))

;;; Tie widget and balloon to context and actions

(define (inactive-reference-focus)
  (and (inside? 'inactive)
            (or
             (reference-context? (focus-tree))
             (label-context? (focus-tree)))))

;; Widget in context menu
(tm-menu (texmacs-popup-menu)
  (:require (inactive-reference-focus))
  (former)
  ---
  ("Show labels" (top-window enum-labels "Insert labels")))

;; Balloon to keyboard shortcut
(kbd-map
  (:require (inactive-reference-focus))
  ("C-l C-l" (label-balloon)))






2 Likes

For \ref it works much faster than for \label . Another observation: in pop-up the reference with sign < :
eq:m<mu has the correct form but in enum widget, it has worn form eq:m<меньше>mu . The <меньше> in Russian is <smaller> in English (I use the Russian language).

I did not expect that. Let me think. I will let you know.

Maybe I know what is happening: the Scheme representation of the < symbol is being passed onto the string. Let me think. If I do not know how to transform it back into < I will ask the developers.

I saw the effect in the Russian language and also in Italian and German. It is probably a bug; inside the strings in the Scheme code it should be not <меньше> but <less>, which is converted automatically by TeXmacs into the Unicode symbol. I guess this from some tests with the Scheme command line (I issued (insert “m<меньше>mu”) and the analogous form with the Italian <minore> :slight_smile: ). when it is <меньше> it is converted into a red-colored string that is made only by <>, and when it is <minore> into the red-colored string <minore> (the red color signals error I imagine). I am going to ask the developers.

I am going to tackle the other issue after I figure out this one.

G

I have posted in the mailing list but did not yet receive an answer. I have a refined guess on what is happening: TeXmacs considers items in the “enum” widget to be menu items, and translates them in this context.
Try to put inside a label the word “edit” or “home” and you should see them translated into Russian in “interface” context— and if you write “house” it will remain “house”.

Yes, you are right. It is funny :slight_smile: . Instead of home the Russian translation дом appears and instead of edit the Russian редактировать appears.

Dear @JoePass and @jeroen, we have an answer:
http://lists.texmacs.org/wws/arc/texmacs-users/2021-03/msg00001.html
I’ll read file-menu.scm soon—hopefully we will have a nice “verbatim” menu.

This worked in the short tests that I made.
Please let me know if now the menu entries are the labels or the translated labels.

;;=============================
;;Label list widget and balloon
;;=============================



;; the balloon shows all the labels that match the start of the current
;; reference or label (except the current label, which matches by definition,
;; if in a label)

(use-modules (utils library cursor)) ; for the with-cursor macro (Scheme
					; developer's manual, pag. 20)



;;; indexed sorting

(define (sort-list-indexed lst proc)
	(let* ((lst-indexed
	       (map (lambda (x y) (cons x  y)) 
		    lst (iota (length lst))))
	       (lst-indexed-sorted
		(sort-list lst-indexed (lambda (x y) (proc (car x) (car y))))))
	  (values (map car lst-indexed-sorted) (map cdr lst-indexed-sorted))))

;;; From srfi-1

 (define (partition pred lis)
  (check-arg procedure? pred partition)
  (let recur ((lis lis))
    (if (null-list? lis) (values lis lis)       ; Use NOT-PAIR? to handle dotted lists.
        (let ((elt (car lis))
              (tail (cdr lis)))
          (receive (in out) (recur tail)
            (if (pred elt)
                (values (if (pair? out) (cons elt in) lis) out)
                (values in (if (pair? in) (cons elt out) lis))))))))

;; In the introductory comments to srfi-1 (because part of r5rs)
   (define (check-arg pred val caller)
      (let lp ((val val))
        (if (pred val) val (lp (error "Bad argument" val pred caller)))))


 (define (null-list? l)
  (cond ((pair? l) #f)
        ((null? l) #t)
        (else (error "null-list?: argument out of domain" l))))


;;; indexed partitioning

;; partitions a list according to pred, then conses one partition to the list
;; equivalence-classes and passes the new list equivalence-classes and the
;; other partition to a copy of itself (recursively)
(define (partition-equivalence-classes-aux pred equivalence-classes lst)
  (cond ((null? lst) equivalence-classes) ; base case
	(values
	  (call-with-values
	      (lambda ()
		(partition (lambda (x) (pred (car lst) x)) lst))
	    (lambda (l1 l2)
	      (partition-equivalence-classes-aux
	       pred
	       (cons l1 equivalence-classes)
	       l2))))))

(define (partition-equivalence-classes pred lst)
  (partition-equivalence-classes-aux pred '() lst))

;; marks each element of lst with its position index, then partitions the new
;; list in equivalence classes using equivalence of the car as predicate.
;; In this way, we have a partitioned list and we know which position each
;; element had in the original list
(define (partition-equivalence-classes-indexed pred lst)
  (let ((lst-indexed (map (lambda (x y) (cons x y))
			  lst (iota (length lst)))))
    (partition-equivalence-classes
     (lambda (x y) (pred (car x) (car y)))
     lst-indexed)))

;;; index elements of a list of strings starting from the second element,
;;; adding the index at the end of the string

;; Generate a list of indices, turn them into strings, append them to the
;; strings in the list using map.

;; In the previous version of the code it was done applying the function
;; index-pairs-aux recursively


(define (parenthesize-index n)
   (string-join `("(" ,(number->string n) ")") ""))

(define (string-indices lst)
  (cons "" (map parenthesize-index
		(map (cut + <> 2) (iota (- (length lst) 1))))))

(define (index-element elem index-string)
  (cons (string-join `(,(car elem) ,index-string)) (cdr elem)))

(define (index-pairs-from-second lst)
  (map index-element lst (string-indices lst)))



;; The list of indexed strings is organized into equivalence classes; we
;; flatten it before re-ordering it according to the original ordering (saved
;; in the indices in the cdr). Here is the flattening function
(define (flatten lst)
  (cond ((null? lst) lst)
	((not (list? (car lst))) (cons (car lst) (flatten (cdr lst))))
	(else (append (car lst) (flatten (cdr lst))))))



;;; Tree search

(define (biblio-context? t)
  (or (tree-func? t 'bibliography 4)
      (tree-func? t 'bibliography* 5)))

(tm-define (in-biblio-context? t) (tree-search-upwards t biblio-context?))

;; definition of tree-search
;; in progs/kernel/library/tree.scm

;; (define-public (tree-search t pred?)
;;   (with me (if (pred? t) (list t) '())
;;     (if (tree-atomic? t) me
;; 	(append me (append-map (cut tree-search <> pred?)
;; 			       (tree-children t))))))


;; Starting from the standard tree-search, a tree-search function that does not
;; look inside the current focus.
;; If I find the path of (focus-tree) I exit from the function

;; I could write a single search function that does not look inside the current
;; focus and apply it to every case (since we are looking for labels, excluding
;; the current focus in a reference will find all labels)
(define (tree-search-elsewhere t pred?)
  (with me (if (and (pred? t) ) (list t) '())
    (cond
      ((tree-atomic? t) me)
      ((equal? (tree->path (focus-tree)) (tree->path t)) '())
      (else (append me (append-map (cut tree-search-elsewhere <> pred?)
				   (tree-children t)))))))

(tm-define (search-doc-all-labels t)
  (:synopsis "A function that finds all labels that are not part of the bibliography.")
  (tree-search t
    (lambda (s) (and (label-context? s) (not (in-biblio-context? s)))
	    )))

(tm-define (search-doc-elsewhere-labels t)
  (:synopsis "A function that finds all labels outside the current focus that are not part of the
bibliography.")
  (tree-search-elsewhere t
    (lambda (s) (and (label-context? s) (not (in-biblio-context? s)))
	    )))

(tm-define (search-doc-labels t)
  (if (label-context? (focus-tree))
      (search-doc-elsewhere-labels t)
      (search-doc-all-labels t)))


;;; Filter labels that start as the text typed in the label or reference in focus

(tm-define (filter-labels labels str)
  (:synopsis "Keeps the labels whose start is equal to str")
  (filter (lambda (s)
	    (and (>= (string-length s) (string-length str))
		 (string-contains s str 0 (string-length str)))) 
	  labels))
;; first we check if the string is at least as long as the text in the ref or
;; label (arguments of and are evaluated only up to the first that is false)
;; then we check that the label contains the already-typed text (which is now
;; at most as long as the label).
;; The two indices 0 and (string-length str) cause the comparison to be made
;; only to the beginning substring of s of length equal to the length of str.
;; I think that the indices of string-contains behave like the indices of
;; substring (first included, last excluded), I tested this in one case only:
;; (string-contains "test " "test" 0 4) $0
;; (string-contains "test " "test" 0 3) $#f



;;; Index repeated labels to distinguish them

;; The "enum" widget provided by TeXmacs filters the list to keep only unique
;; entries. We want to see all labels, so we add an index to repeated entries
;; applying the function index-repeated-entries, which needs the function
;; order-indexed-list to put its elements in the original order after it marked
;; them


;; order-indexed-list puts the element marked with i at the i-th place in the
;; output list; for this, it uses imperative code
(define (order-indexed-list lst)
  (let ((ordered-lst (make-list (length lst))))
    (begin
      (do ((i 0 (1+ i))) ((>= i (length lst)))
	(list-set! ordered-lst
		   (cdr (list-ref lst i))
		   (car (list-ref lst i))))
      ordered-lst)))

(define (index-repeated-entries lst)
  (order-indexed-list
   (flatten (map index-pairs-from-second
		 (partition-equivalence-classes-indexed equal? lst)))))



;;; Build label list

;; use search-doc-labels function instead of the standard search-labels, that
;; finds the labels defined in the bibliography as well.
;; The search-doc-labels function behaves differently if in a label (excludes
;; the current focus)
(define (label-list)
  (let ((ls (search-doc-labels (buffer-tree))))
    (map (lambda (l) (tree->string (tm-ref l 0))) ls)))
;; (define (label-list)
;;   (let ((ls (search-doc-labels (buffer-tree))))
;;     (map (lambda (l) (cadr (tree->stree l))) ls)))


;;; Widget

;; An insert function that inserts a string only up to before the last blank
(define (keep-till-first-blank str)
  ;; (display "keep-till-first-blank\n")
  (let* ((ind-first-blank (string-index str #\space)))
    ;; if we did not find a blank,
    ;; ind-first-blank is false: keep the
    ;; whole string
    (if ind-first-blank
	(substring str 0 ind-first-blank)
	str)))


;; The enum widget treats the entries of its list as if they were menu entries,
;; translating them into the language set for the interface.  In order to
;; prevent this, we wrap each list entry in a verbatim tag (see
;; http://lists.texmacs.org/wws/arc/texmacs-users/2021-03/msg00001.html).  When
;; using the selected element (saved inside the "answer" variable) we then need
;; to extract the string element out of the verbatim tag.
(tm-widget (enum-labels)
  (enum (with-cursor ; place the selected item at the end of the current focus
	    (path-end (root-tree) (tree->path (focus-tree)))
	  (insert (keep-till-first-blank (cadr answer))))
					; We use (cadr answer) to extract the
					; string out of the verbatim tag
					; keep-till-first-blank acts on (cadr
					; answer), because in the list we want
					; to display the combination of label
					; and index
	(map (lambda (l) `(verbatim ,l))
	     (index-repeated-entries (label-list)))
	"Choose label ..."
"24em"))

;; Attempt to fix the "<меньше>" issue
;; Does not work, the issue is probably a bug
;; (tm-widget (enum-labels)
;;   (enum (with-cursor ; place the selected item at the end of the current focus
;; 	    (path-end (root-tree) (tree->path (focus-tree)))
;; 	  (insert (keep-till-first-blank answer)));keep-till-first-blank acts
;; 					;on answer, because in the list we want
;; 					;to display the combination of label
;; 					;and index
;; 	(map stree->tree (index-repeated-entries (label-list))) "Choose label ..."
;; "24em"))


;;; Balloon

(tm-define (label-balloon)
  (let* ((focus-string (cadr (tree->stree (focus-tree))))
         (ll (filter-labels ; keep only labels that start with the text in focus tree
	      (label-list)
	      focus-string)))
    (display-balloon (cursor-tree) `(document ,@ll) "auto" "auto" "keyboard")))

;; (tm-define (label-balloon)
;;   (let* ((focus-string (cadr (tree->stree (focus-tree))))
;;          (ll (filter-labels ; keep only labels that start with the text in focus tree
;; 	      (label-list)
;; 	      focus-string)))
;;     (display-balloon (cursor-tree) `(document ,@(map stree->tree ll)) "auto" "auto" "keyboard")))

;;; Tie widget and balloon to context and actions

(define (inactive-reference-focus)
  (and (inside? 'inactive)
            (or
             (reference-context? (focus-tree))
             (label-context? (focus-tree)))))

;; Widget in context menu
(tm-menu (texmacs-popup-menu)
  (:require (inactive-reference-focus))
  (former)
  ---
  ("Show labels" (top-window enum-labels "Insert labels")))

;; Balloon to keyboard shortcut
(kbd-map
  (:require (inactive-reference-focus))
  ("C-l C-l" (label-balloon)))


I checked It works well for \ref \eqref and \label even with preview-ref started. But nothing happens with Ctl-l Ctr-l clicking (with and without preview-ref, with and without ridged paper style).

This can be because of two things, not exclusive of each other (according to how the program works and my experience using it in TeXmacs):

  1. You are in a label, which is unique (i.e. there is no other label which starts in the same way). The balloon shows all other labels that start like the current label; if you are in a reference, it shows all labels that starts like the reference. If you are in a label with unique name, pls. either try the shortcut in a reference or in a label which starts like some other labels.

  2. TeXmacs is not recognizing the shortcut. It happened to me, but I did not write it down and I forgot when (perhaps when testing under Windows). If you are not in case 1., pls. try and change the shortcut
    (for example, try “C-F8” like @jeroen set it to)

For point .1 I will try and document the widget code better than it is now, but it will take time.

Please let me know. We should be able to make it work :slight_smile:

It works but with Theme->Plain only. I use ridged paper and with this theme, it does not work. Also, I observed that it works slowly with \label. But without a balloon the functionality is well.

Which one of the two was the reason? i.e. you were in a unique label or did you need to change shortcut? Or something else?

IMHO that is a bug of TeXmacs (maybe worth reporting)

I will think about this. I do not see a possible reason while I am writing, but if something comes to my mind I will write again.

I just forget that balloon is working when \ref \eqref or \label has started :).

Sorry, I did not understand. Could you try explaining in another way?

To use C-l C-l I have to print first \ref, \eqref, or \lebel and after use C-l C-l. But I used C-l C-l without \ref, \eqref, or \lebel.

1 Like

Thanks for writing this function. I think it’s essential for a smooth writing experience.

I found that I can make the balloon stable with preview-ref on by holding the shortcut. It does have a down side, though. The focus menu will freeze for some time and the longer I holds, the longer the time will be.

2 Likes