0

I have the following elisp functions to show a table by calling make-table.

Associated with each completion framework there is a number. 0 means feature not loaded; 1 feature loaded; 2 feature loaded and user performed customisation; 3 feature loaded, customisation performed and mode enabled.

The information is stored in a vector array (setq selectr [3 2 1 1 0]), corresponding to the completion features (icomplete, icomplete-vertical, ivy, vertico, helm).

The intention is to produce the following table

+------------------+-----+-----+-----+
|Completion        |1    |2    |3    |
+------------------+-----+-----+-----+    
|built-in          |xxxxx|xxxxx|xxxxx| 
+------------------+-----+-----+-----+
|icomplete         |xxxxx|xxxxx|xxxxx|
+------------------+-----+-----+-----+
|icomplete-vertical|xxxxx|xxxxx|     |
+------------------+-----+-----+-----+
|ivy               |xxxxx|xxxxx|     |
+------------------+-----+-----+-----+
|vertico           |xxxxx|     |     |
+------------------+-----+-----+-----+
|helm              |     |     |     |
+------------------+-----+-----+-----+


(defun text-of-table (table)
  "Insert a header and the first row  and then loop over the
table, formatting each row and concatenating the rows with
newlines."

  (concat "Completion |1    |2    |3    | \n"
      "built-in  |xxxxx|xxxxx|xxxxx| \n"
      (mapconcat
         ;; function
         (lambda (x)
           (format "%s| %s | %s \n" (nth 0 x) (nth 1 x) (nth 2 x)))
             ;;
         table
         "\n")))

(defun table-of-frameworks ()
  "The returned table is represented as a list of rows; each row
is represented as a four-element list: the name of the framework
and the strings \"xxxxx\", depending on whether the number is    
0, 1, 2 ,or 3."

  (let ( (frameworks
        '(icomplete icomplete-vertical ivy vertico helm)) )

    (mapcar
       ;; Function
       (lambda (x)
     (list (symbol-name x)
           (if (featurep x) "xxxxx|xxxxx|xxxxx|" "|||")))
       ;;
       frameworks)))

(defun make-table ()
  (interactive)
  (let ((beg (point)))
    (insert (text-of-table (table-of-frameworks)))
    (table-capture beg (point) "|" "\n")))
3
  • I don't understand the specification: care to elaborate? What do the columns mean? Please edit the question: do not clarify in a comment.
    – NickD
    Nov 5, 2022 at 14:44
  • Associated with each completion framework there is a number. 0 means feature not loaded; 1 feature loaded; 2 feature loaded and user performed customisation; 3 feature loaded, customisation performed and mode enabled.
    – Dilna
    Nov 6, 2022 at 4:47
  • Please edit the question: do not clarify in a comment.
    – NickD
    Nov 6, 2022 at 16:41

1 Answer 1

0

You can use seq-mapn to iterate over two sequences simultaneously. Then you can use mapconcat to create the string, and use y (from your selectr sequence) as a counter in its 'function' argument. There exists the nice 'special form' prog1 that makes it possible to lower the counter after the if form, but return the value of the if form (the first function in the prog1 body).

After applying these 'tricks' your first two functions would look as follows, and produce the result you ask for:

(defun text-of-table (table)
  "Insert a header and the first row  and then loop over the
table, formatting each row and concatenating the rows with
newlines."

  (concat "Completion |1    |2    |3    | \n"
          "built-in  |xxxxx|xxxxx|xxxxx| \n"
          (mapconcat
           ;; function
           (lambda (x)
             (format "%s|%s\n" (nth 0 x) (nth 1 x)))
           table
           "\n")))

(defun table-of-frameworks ()
  "The returned table is represented as a list of rows; each row
is represented as a four-element list: the name of the framework
and the strings \"xxxxx\", depending on whether the number is
0, 1, 2 ,or 3."

  (let ((frameworks '(icomplete icomplete-vertical ivy vertico helm))
        (selectr [3 2 1 1 0]))

    (seq-mapn (lambda (x y)
                (list (symbol-name x)
                      (if (featurep x)
                          (mapconcat (lambda (s)
                                       (prog1
                                           (if (> y 0) (concat "xxxxx" s) s)
                                         (setq y (1- y))))
                                     (split-string "|||" "" t))
                        "|||")))
              frameworks selectr)))

or you could use the simple

(mapconcat #'identity
           (append (make-list y "xxxxx|") (make-list (- 3 y) "|")))

and there are probably many more clever ways to achieve it.

Simply load the functions above and use your make-table function

As mentioned by @nickd, the code would probably be more robust when you first associate the framework with the selector (e.g. in an alist), and then simply map over the association(-list) (and appropriately use the car and cdr).

3
  • 1
    It would be better if the selector was attached to the appropriate framework to begin with. Parallel lists have to be kept in sync manually, making it twice as likely that an error will creep in.
    – NickD
    Nov 5, 2022 at 18:50
  • Good point! I simply assume(d) that the frameworks and the selectr are separate for some 'good' reason. Nov 5, 2022 at 18:54
  • I doubt it: that's why I asked for clarification.
    – NickD
    Nov 5, 2022 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.