Table des matières en colonnes

J'ai le problème avec votre code, où j'ai remplacé les trois lignes height et mis un % sur le \tocAct, voir ci-dessous.

Après, c'est une question de temps: si quelqu'un trouve la solution en 5 minutes et que le code survit aux màj, autant utiliser le travail déjà fait, mais sinon, je préfère investir quelques heures en python que des semaines en scheme, d'autant que j'ai déjà programmé des indexes de cette manière et que cela fonctionne bien.

\version "2.24.1"
% Voir https://lists.gnu.org/archive/html/lilypond-user-fr/2022-08/msg00074.html
% et https://gitlab.com/lilypond/lilypond/-/issues/6355
#(let ((default-table-of-contents make-table-of-contents-markup-list))
   (define-markup-list-command (table-of-contents layout props) ()
     (let* ((result (interpret-markup-list layout props (default-table-of-contents)))
            (alist (ly:output-def-lookup layout 'label-alist-table))
            (parent (ly:output-def-parent layout)))
       (when (not (null? parent))
         (ly:output-def-set-variable! parent 'label-alist-table alist))
       result)))


#(use-modules (ice-9 match))

#(define (group-to-fill-partial-sums lst weight threshold initial)
   (let loop ((lst lst)
              (i 0)
              (partial-sum (initial 0))
              (acc '()))
     (match lst
       (()
        (reverse! (map reverse! acc)))
       ((elt . rest)
        (let* ((elt-weight (weight elt))
               (new-sum (+ partial-sum elt-weight)))
          (cond
           ((null? acc)
            (loop rest i new-sum (list (list elt))))
           ((<= new-sum threshold)
            (loop rest i new-sum (cons (cons elt (car acc))
                                            (cdr acc))))
           (else
            (loop rest
                  (1+ i)
                  (+ (initial (1+ i))
                     elt-weight)
                  (cons (list elt)
                        acc)))))))))

#(define (index-map f . lsts)
   (let loop ((lsts lsts)
              (i 0))
     (if (any null? lsts)
         '()
         (cons (apply f i (map car lsts))
               (loop (map cdr lsts)
                     (1+ i))))))

#(ly:register-stencil-expression 'new-toc-group)
#(define-markup-command (new-toc-group layout props arg) (markup?)
   (let* ((stil (interpret-markup layout props arg))
          (expr (ly:stencil-expr stil))
          (x (ly:stencil-extent stil X))
          (y (ly:stencil-extent stil Y)))
     (ly:make-stencil `(new-toc-group ,expr)
                      x
                      y)))

#(define-markup-list-command (multicolumn-toc layout props columns) (index?)
   #:properties ((baseline-skip)
                 (padding 5)
                 (line-width))
   (let ((width (/ (- line-width (* padding (1- columns)))
                     columns))
 (height (- (ly:output-def-lookup layout 'paper-height) 30.0)))
     (let ((mkup (ly:output-def-lookup layout 'tocItemMarkup)))
       (ly:output-def-set-variable! layout 'tocItemMarkup (make-override-markup
                                                           `(line-width . ,width)
                                                           mkup)))
     (match-let*
           (((title . ungrouped-stils)
             (interpret-markup-list layout
                                    props
                                    (make-table-of-contents-markup-list)))
            (stils
             (let loop ((ungrouped-stils ungrouped-stils)
                        (group '())
                        (acc '()))
               (match ungrouped-stils
                 (()
                  (reverse!
                   (map (lambda (group-elts)
                          (let ((rev-group-elts (reverse! group-elts)))
                            (stack-stencils Y DOWN baseline-skip rev-group-elts)))
                        (cons group acc))))
                 ((stil . rest)
                  (match (ly:stencil-expr stil)
                    (('new-toc-group expr)
                     (let* ((x (ly:stencil-extent stil X))
                            (y (ly:stencil-extent stil Y))
                            (unwrapped (ly:make-stencil expr x y)))
                       (loop rest
                             (list unwrapped)
                             (cons group acc))))
                    (_
                     (loop rest
                           (cons stil group)
                           acc)))))))
            (split (group-to-fill-partial-sums
                    stils
                    (lambda (stil)
                      (+ (interval-length (ly:stencil-extent stil Y))
                         baseline-skip))
                    height
                    (let ((title-height (interval-length (ly:stencil-extent title Y))))
                      (lambda (i)
                        (if (< i columns)
                            title-height
                            0)))))
            (cols (group-to-fill-partial-sums
                   split
                   (const 1)
                   columns
                   (const 0))))
       (cons title
             (map (lambda (page-cols)
                    (apply ly:stencil-add
                           (index-map
                            (lambda (i col-stils)
                              (ly:stencil-translate-axis
                               (stack-stencils Y DOWN baseline-skip col-stils)
                               (* i (+ width padding))
                               X))
                            page-cols)))
                  cols)))))




\paper {
  ragged-last-bottom = ##t
  ragged-last = ##f
  %% Attention : s'il y a plusieurs éléments à l'intérieur du tocActMarkup,
  %% ne pas faire \new-toc-group { ... } mais \new-toc-group \line { ... }
  tocActMarkup = \markup \new-toc-group \line {
    \vspace #1
    \hspace #-4
    \italic \fromproperty #'toc:text
  }
  tocItemMarkup = \markup
  \fontsize #-2
  \fill-line {
    \fill-with-pattern #1.5 #CENTER .
    \line {
      \hspace #-6.5 %% Cancelling the first level's tocIndentMarkup
      \fromproperty #'toc:indent \fromproperty #'toc:text
      \hspace #2
    }
    \fromproperty #'toc:page
  }
  tocTitleMarkup =
  \markup {
    \column {
      \vspace #3
      \fill-line { \fontsize #9 "My Real Book" }
       \vspace #1
      \fill-line { \fontsize #3 "For C Instruments" }
       \vspace #2
    }
  }
}

tocAct =
#(define-music-function (label text) (symbol-list-or-symbol? markup?)
   (add-toc-item! 'tocActMarkup text label))


\bookpart {
  \paper {
    left-margin = 20
    right-margin = 15
  }
  \markuplist
  % les \override sont facultatifs
  \override #'(padding . 10)
  \override #'(baseline-skip . 1)
  \multicolumn-toc #4
}

\bookpart {
  $@(map (lambda (i)
           (let ((sym (gensym "act")))
             #{
       %        \tocAct #sym #(format #f "Pièce ~a" i)
               \tocItem #(list sym 'sheet) "Lead sheet"
               \tocItem #(list sym 'bass) "Bass line"
               c'
               #}))
         (iota 300 1))
}

Là, c'est normal par contre : le code demande à ce que chaque groupe indivisible d'entrées de la table des matières (qui ne doit pas être séparé entre plusieurs colonnes) soit démarré par un \new-toc-group. Comme vous avez enlevé le \tocAct et que le \new-toc-group est dans le tocActMarkup, il n'y a plus de \new-toc-group du tout, donc non seulement la table des matières se retrouve sur la deuxième page, mais surtout elle ne se répartit plus en colonnes du tout, ce que vous pouvez régler en changeant le tocItemMarkup = \markup en tocItemMarkup = \markup \new-toc-group si vous n'avez pas comme Vincent de groupes indivisibles (comme les parties de différents instruments pour une même pièce).

D'accord, alors j'ai essayé de modifier votre code, pour qu'il se rapproche du mien:

  • j'ai effacé le \paper du début
  • j'ai commenté les premières lignes qui ne changent rien à la compilation (ont-elles encore une utilité?)
  • j'ai regroupé les instructions \paper de la fin et je les ai modifiées.
  • j'ai mis le \tocAct en commentaire et ajouté \new-to-group au tocItemMarkup
  • j'ai ajouté un \paper avec un autre formatage

Cela donne le même résultat que dans mon code, avec un problème de chevauchement.

Et si je veux activer le \toAct, je ne comprends pas comment je peux transposer la ligne \tocAct #sym #(format #f "Pièce ~a" i) dans mon code, j'ai essayé probablement à tord avec \tocAct "act" "Titre".

J'ai aussi essayé (height (- (ly:output-def-lookup layout 'paper-height) 30.0))), mais cela ne résout pas le chevauchement.

\version "2.24.1"

% Voir https://lists.gnu.org/archive/html/lilypond-user-fr/2022-08/msg00074.html
% et https://gitlab.com/lilypond/lilypond/-/issues/6355
% #(let ((default-table-of-contents make-table-of-contents-markup-list))
%    (define-markup-list-command (table-of-contents layout props) ()
%      (let* ((result (interpret-markup-list layout props (default-table-of-contents)))
%             (alist (ly:output-def-lookup layout 'label-alist-table))
%             (parent (ly:output-def-parent layout)))
%        (when (not (null? parent))
%          (ly:output-def-set-variable! parent 'label-alist-table alist))
%        result)))
% 
% #(use-modules (ice-9 match))

#(define (group-to-fill-partial-sums lst weight threshold initial)
   (let loop ((lst lst)
              (i 0)
              (partial-sum (initial 0))
              (acc '()))
     (match lst
            (()
             (reverse! (map reverse! acc)))
            ((elt . rest)
             (let* ((elt-weight (weight elt))
                    (new-sum (+ partial-sum elt-weight)))
               (cond
                ((null? acc)
                 (loop rest i new-sum (list (list elt))))
                ((<= new-sum threshold)
                 (loop rest i new-sum (cons (cons elt (car acc))
                                            (cdr acc))))
                (else
                 (loop rest
                       (1+ i)
                       (+ (initial (1+ i))
                          elt-weight)
                       (cons (list elt)
                             acc)))))))))

#(define (index-map f . lsts)
   (let loop ((lsts lsts)
              (i 0))
     (if (any null? lsts)
         '()
         (cons (apply f i (map car lsts))
               (loop (map cdr lsts)
                     (1+ i))))))

#(ly:register-stencil-expression 'new-toc-group)
#(define-markup-command (new-toc-group layout props arg) (markup?)
   (let* ((stil (interpret-markup layout props arg))
          (expr (ly:stencil-expr stil))
          (x (ly:stencil-extent stil X))
          (y (ly:stencil-extent stil Y)))
     (ly:make-stencil `(new-toc-group ,expr)
                      x
                      y)))

#(define-markup-list-command (multicolumn-toc layout props columns) (index?)
   #:properties ((baseline-skip)
                 (padding 5)
                 (line-width))
   (let ((width (/ (- line-width (* padding (1- columns)))
                   columns))
         (height (- (ly:output-def-lookup layout 'paper-height)
                    (ly:output-def-lookup layout 'top-margin)
                    (ly:output-def-lookup layout 'bottom-margin))))
     (let ((mkup (ly:output-def-lookup layout 'tocItemMarkup)))
       (ly:output-def-set-variable! layout 'tocItemMarkup (make-override-markup
                                                           `(line-width . ,width)
                                                           mkup)))
     (match-let*
      (((title . ungrouped-stils)
        (interpret-markup-list layout
                               props
                               (make-table-of-contents-markup-list)))
       (stils
        (let loop ((ungrouped-stils ungrouped-stils)
                   (group '())
                   (acc '()))
          (match ungrouped-stils
                 (()
                  (reverse!
                   (map (lambda (group-elts)
                          (let ((rev-group-elts (reverse! group-elts)))
                            (stack-stencils Y DOWN baseline-skip rev-group-elts)))
                        (cons group acc))))
                 ((stil . rest)
                  (match (ly:stencil-expr stil)
                         (('new-toc-group expr)
                          (let* ((x (ly:stencil-extent stil X))
                                 (y (ly:stencil-extent stil Y))
                                 (unwrapped (ly:make-stencil expr x y)))
                            (loop rest
                                  (list unwrapped)
                                  (cons group acc))))
                         (_
                          (loop rest
                                (cons stil group)
                                acc)))))))
       (split (group-to-fill-partial-sums
               stils
               (lambda (stil)
                 (+ (interval-length (ly:stencil-extent stil Y))
                    baseline-skip))
               height
               (let ((title-height (interval-length (ly:stencil-extent title Y))))
                 (lambda (i)
                   (if (< i columns)
                       title-height
                       0)))))
       (cols (group-to-fill-partial-sums
              split
              (const 1)
              columns
              (const 0))))
      (cons title
            (map (lambda (page-cols)
                   (apply ly:stencil-add
                          (index-map
                           (lambda (i col-stils)
                             (ly:stencil-translate-axis
                              (stack-stencils Y DOWN baseline-skip col-stils)
                              (* i (+ width padding))
                              X))
                           page-cols)))
                 cols)))))

tocAct =
#(define-music-function (label text) (symbol-list-or-symbol? markup?)
   (add-toc-item! 'tocActMarkup text label))

#(set! paper-alist (cons '("Legal Landscape" . (cons (* 356 mm) (* 216 mm))) paper-alist))

\paper {
  #(set-paper-size "Legal Landscape")
  ragged-bottom = ##t
  print-page-number = ##f
  top-margin = 1\mm
  bottom-margin = 1\mm
  top-system-spacing.basic-distance = 1
  top-markup-spacing.basic-distance = 1
  left-margin = 7\mm
  right-margin = 7\mm
  inner-margin = 1\mm
  outer-margin = 1\mm
  binding-offset = 1\mm
}

\bookpart 
{
  \paper
  {
    oddHeaderMarkup = \markup "Test"
    evenHeaderMarkup = \oddHeaderMarkup
    oddFooterMarkup = ""
    evenFooterMarkup = ""
    %% Attention : s'il y a plusieurs éléments à l'intérieur du tocActMarkup,
    %% ne pas faire \new-toc-group { ... } mais \new-toc-group \line { ... }
    tocActMarkup =  \markup \new-toc-group \line { \large \bold \vspace #2 \fromproperty #'toc:text }  
  tocItemMarkup = \markup \new-toc-group  { \fromproperty #'toc:text   }
  tocTitleMarkup =  ""
}
\markuplist
% les \override sont facultatifs
\override #'(padding . 10)
\override #'(baseline-skip . 1)
\multicolumn-toc #4
}

\bookpart {
  $@(map (lambda (i)
  (let ((sym (gensym "act")))
  #{
     \tocAct #sym #(format #f "Pièce ~a" i)
    \tocItem #(list sym 'sheet) "Lead sheet"
    \tocItem #(list sym 'bass) "Bass line"
    c'
    #}))
  (iota 300 1))
}

Finalement, j'ai écrit un script python pour générer ma table des matières.

Le rendu me convient bien, j'ai pu aussi solutionner qu'une catégorie ne s'affiche pas en fin de colonne, s'il n'y a pas au moins un élément en-dessous.

Et comme je compilais déjà le recueil avec un script, cela s'intègre de manière transparente.

Ce n'est pas aussi élégant que le Scheme, mais pour avoir lu la documentation fort bien faite de Jean, le problème est qu'il manque toute l'intégration avec Lilypond.

Or, vu la courbe d'apprentissage, je pense que cela ne vaut la peine que si l'on envisage de participer activement au développement de Lilypond.