How can I see list of labels?

My main tools are ack and grep:

ack --type=ts somemacro|grep macro

to find macro definitions, or

ack --type=scheme somefunction|grep define

for scheme functions.

There is a scrollable widget which you need to use if you want scrollbars. Put it inside the balloon widget. You may want to look at the Help, there there is a list of available widgets, and grepping in the TeXmacs/prog directory for tm-widget you can find various examples of widget construction code.

@JoePass is seeing scrollbars in a balloon without the scrollable widget (How can I see list of labels?). I do not understand what is happening.

I made “Insert -> Note -> Balloon” First entry appears in the text but second does not, the black field only. I added your code and the result is the same but with smaller black pop-up window. For cleanliness experiment, I deleted my-ini file. The same black window. I see that the baloon does not work itself.
I noted that the size of black window depends on the text in the second entry. That is why the letter appear in the filed but can not shown.

Wow. I found what is the root of the problem! I use theme Ridger Paper. If I use Plain then every thing works well. Is it bug? The close problem was in my another post How to emphasize an equation with color box?. The colors do not appear in this theme.

I verified - balloon does not work in any theme except plain.

2 Likes

Блин, that’s a really odd bug :grinning:

You could file a bug at https://savannah.gnu.org/bugs/?group=texmacs

I could also do it for you if you prefer.

I just put it in savannah.

1 Like

Here is the last version of the widget and balloon. I found the definition of the tree-search function and modified it not to look inside the focus. I don’t have a grasp of what data structure is a tree, so I could not cut the “focus branch” from the tree to search (I omit details).

Also, in the widget repeated labels are indexed (it is good by itself I think, and also necessary because the “enum” widget filters its list to keep only one copy of each element); when inserting, the index is omitted.

It could also be good to insert only the “rest of the matching label” at the end of the text in the current focus, but I have to think how to do it. Also in this case I/we would have to think on what to do with non-matching labels.
At the moment I am showing all labels in the widget, and only matching labels (without indexing) in the balloon.

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


;;; 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

;; The following functions work well together because in the input list of
;; labels found by search-doc-labels there are no spaces, so I can apply the
;; index-equal-elements to the cdr of the list after I have already modified it
;; with index-equal-elements applied to the whole list (using as a comparison
;; the car of the list)---the modifications neither cause new matches, nor
;; exclude already-existing matches

(define (index-equal-elements element lst n)
  (cond ((null? lst) lst)
	((equal? (car lst) element)
	 (cons (string-join `(,(car lst) " (" ,(number->string n) ")") "")
	       (index-equal-elements element (cdr lst) (+ n 1))))
	(else  (cons (car lst) (index-equal-elements element (cdr lst) n)))))

(define (index-repeated-entries lst)
  (cond ((null? lst) lst)
	(else (cons (car lst)
		    (index-repeated-entries
		     (index-equal-elements (car lst) (cdr lst) 2))))))


;;; 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 (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

In my usage it works for \label command (the pop-up appears without selection possibility), but for \ref the pop-up appears and very fast disappears.

With or without preview-ref?

It works without preview-ref.

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”.