--- /dev/null
+\version "2.11.55"
+
+\header {
+ texidoc = "A book can be split into several parts with different paper settings,
+using @code{\\bookpart}.
+
+Fonts are loaded into the top-level paper.
+Page labels are also collected into the top-level paper."
+}
+
+#(set-default-paper-size "a6")
+
+#(define-markup-command (roman-page-number layout props) ()
+ (let ((page-number (chain-assoc-get 'page:page-number props)))
+ (interpret-markup layout props (format #f "~@r" page-number))))
+
+\book {
+ \tocItem \markup "First part"
+ \header { title = "Book with several parts" }
+ \markup { First part }
+ \markup { with default paper settings. }
+
+ \bookpart {
+ \paper {
+ left-margin = 20\mm
+ right-margin = 20\mm
+ line-width = 65\mm
+ evenHeaderMarkup = \markup \fill-line { \roman-page-number "SECOND PART" \null }
+ oddHeaderMarkup = \markup \fill-line { \null "SECOND PART" \roman-page-number }
+ }
+ \tocItem \markup "Second part"
+ \markup \justify { Second part, with different margins and page header. }
+ { c' }
+ }
+
+ \tocItem \markup "Third part"
+ \markup { Third part }
+ \markuplines \table-of-contents
+}
return x;
}
+LY_DEFINE (ly_make_book_part, "ly:make-book-part",
+ 1, 0, 0, (SCM scores),
+ "Make a @code{\\bookpart} containing @code{\\scores}.")
+{
+ Book *book = new Book;
+ book->scores_ = scm_append (scm_list_2 (scores, book->scores_));
+
+ SCM x = book->self_scm ();
+ book->unprotect ();
+ return x;
+}
+
LY_DEFINE (ly_book_process, "ly:book-process",
4, 0, 0, (SCM book_smob,
SCM default_paper,
book->add_score (score);
return SCM_UNSPECIFIED;
}
+
+LY_DEFINE (ly_book_add_bookpart_x, "ly:book-add-bookpart!",
+ 2, 0, 0, (SCM book_smob, SCM book_part),
+ "Add @var{book_part} to @var{book-smob} book part list.")
+{
+ LY_ASSERT_SMOB (Book, book_smob, 1);
+ Book *book = unsmob_book (book_smob);
+ book->add_bookpart (book_part);
+ return SCM_UNSPECIFIED;
+}
paper_ = 0;
header_ = SCM_EOL;
scores_ = SCM_EOL;
+ bookparts_ = SCM_EOL;
input_location_ = SCM_EOL;
smobify_self ();
paper_ = 0;
header_ = SCM_EOL;
scores_ = SCM_EOL;
+ bookparts_ = SCM_EOL;
input_location_ = SCM_EOL;
smobify_self ();
t = SCM_CDRLOC (*t);
newscore->unprotect ();
}
+
+ t = &bookparts_;
+ for (SCM p = s.bookparts_; scm_is_pair (p); p = scm_cdr (p))
+ {
+ Book *newpart = unsmob_book (scm_car (p))->clone ();
+
+ *t = scm_cons (newpart->self_scm (), SCM_EOL);
+ t = SCM_CDRLOC (*t);
+ newpart->unprotect ();
+ }
}
Input *
if (book->paper_)
scm_gc_mark (book->paper_->self_scm ());
scm_gc_mark (book->scores_);
+ scm_gc_mark (book->bookparts_);
scm_gc_mark (book->input_location_);
return book->header_;
scores_ = scm_cons (s, scores_);
}
+void
+Book::set_parent (Book *parent)
+{
+ if (!paper_)
+ {
+ paper_ = new Output_def ();
+ paper_->unprotect ();
+ }
+ paper_->parent_ = parent->paper_;
-/* Concatenate all score outputs into a Paper_book
- */
-Paper_book *
-Book::process (Output_def *default_paper,
- Output_def *default_layout)
+ if (header_ == SCM_EOL)
+ {
+ header_ = ly_make_anonymous_module (false);
+ if (ly_is_module (parent->header_))
+ ly_module_copy (header_, parent->header_);
+ }
+}
+
+void
+Book::add_bookpart ()
+{
+ if (scm_is_pair (scores_))
+ {
+ /* If scores have been added to this book, add them to a child
+ * book part */
+ Book *part = new Book;
+ part->set_parent (this);
+ part->scores_ = scores_;
+ bookparts_ = scm_cons (part->self_scm (), bookparts_);
+ part->unprotect ();
+ scores_ = SCM_EOL;
+ }
+}
+
+void
+Book::add_bookpart (SCM b)
+{
+ add_bookpart ();
+ Book *part = unsmob_book (b);
+ part->set_parent (this);
+ bookparts_ = scm_cons (b, bookparts_);
+}
+
+bool
+Book::error_found ()
{
for (SCM s = scores_; scm_is_pair (s); s = scm_cdr (s))
if (Score *score = unsmob_score (scm_car (s)))
if (score->error_found_)
- return 0;
+ return true;
+
+ for (SCM part = bookparts_; scm_is_pair (part); part = scm_cdr (part))
+ if (Book *bookpart = unsmob_book (scm_car (part)))
+ if (bookpart->error_found ())
+ return true;
+ return false;
+}
+
+Paper_book *
+Book::process (Output_def *default_paper,
+ Output_def *default_layout)
+{
+ return process (default_paper, default_layout, 0);
+}
+
+/* Concatenate all score or book part outputs into a Paper_book
+ */
+Paper_book *
+Book::process (Output_def *default_paper,
+ Output_def *default_layout,
+ Output_def *parent_paper)
+{
Output_def *paper = paper_ ? paper_ : default_paper;
+
+ /* If top book, recursively check score errors */
+ if (!parent_paper && error_found ())
+ return 0;
+
if (!paper)
return 0;
-
+
Paper_book *paper_book = new Paper_book ();
Real scale = scm_to_double (paper->c_variable ("output-scale"));
Output_def *scaled_bookdef = scale_output_def (paper, scale);
-
paper_book->paper_ = scaled_bookdef;
- scaled_bookdef->unprotect ();
-
+ if (parent_paper)
+ paper_book->paper_->parent_ = parent_paper;
paper_book->header_ = header_;
- /* Render in order of parsing. */
- for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s))
+ if (scm_is_pair (bookparts_))
{
- if (Score *score = unsmob_score (scm_car (s)))
- {
- SCM outputs = score
- ->book_rendering (paper_book->paper_, default_layout);
-
- while (scm_is_pair (outputs))
- {
- Music_output *output = unsmob_music_output (scm_car (outputs));
-
- if (Performance *perf = dynamic_cast<Performance *> (output))
- paper_book->add_performance (perf->self_scm ());
- else if (Paper_score *pscore = dynamic_cast<Paper_score *> (output))
- {
- if (ly_is_module (score->get_header ()))
- paper_book->add_score (score->get_header ());
- paper_book->add_score (pscore->self_scm ());
- }
-
- outputs = scm_cdr (outputs);
- }
- }
- else if (Text_interface::is_markup_list (scm_car (s))
- || unsmob_page_marker (scm_car (s)))
- paper_book->add_score (scm_car (s));
- else
- assert (0);
+ /* Process children book parts */
+ add_bookpart ();
+ for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+ {
+ if (Book *book = unsmob_book (scm_car (p)))
+ {
+ Paper_book *paper_book_part = book
+ ->process (paper, default_layout, paper_book->paper_);
+ if (paper_book_part)
+ paper_book->add_bookpart (paper_book_part->self_scm ());
+ }
+ }
+ }
+ else
+ {
+ /* Process scores */
+ /* Render in order of parsing. */
+ for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s))
+ {
+ if (Score *score = unsmob_score (scm_car (s)))
+ {
+ SCM outputs = score
+ ->book_rendering (paper_book->paper_, default_layout);
+
+ while (scm_is_pair (outputs))
+ {
+ Music_output *output = unsmob_music_output (scm_car (outputs));
+
+ if (Performance *perf = dynamic_cast<Performance *> (output))
+ paper_book->add_performance (perf->self_scm ());
+ else if (Paper_score *pscore = dynamic_cast<Paper_score *> (output))
+ {
+ if (ly_is_module (score->get_header ()))
+ paper_book->add_score (score->get_header ());
+ paper_book->add_score (pscore->self_scm ());
+ }
+
+ outputs = scm_cdr (outputs);
+ }
+ }
+ else if (Text_interface::is_markup_list (scm_car (s))
+ || unsmob_page_marker (scm_car (s)))
+ paper_book->add_score (scm_car (s));
+ else
+ assert (0);
+ }
}
return paper_book;
}
-
SCM header_;
Output_def *paper_;
SCM scores_;
+ SCM bookparts_;
SCM input_location_;
Book (Book const &);
VIRTUAL_COPY_CONSTRUCTOR(Book, Book);
Book ();
void add_score (SCM);
+ void add_bookpart ();
+ void add_bookpart (SCM);
+ void set_parent (Book *parent);
+ bool error_found ();
Paper_book *process (Output_def *def_paper,
Output_def *def_layout);
+ Paper_book *process (Output_def *default_paper,
+ Output_def *default_layout,
+ Output_def *parent_paper);
void set_keys ();
};
SCM header_;
SCM header_0_;
SCM scores_;
+ SCM bookparts_;
Output_def *paper_;
Paper_book ();
+ Output_def *top_paper ();
+
void add_score (SCM);
+ void add_bookpart (SCM);
void add_performance (SCM);
SCM performances () const;
Stencil book_title ();
Stencil score_title (SCM);
+ void classic_output_aux (SCM output);
void classic_output (SCM output_channel);
+ int output_aux (SCM output_channel,
+ int first_page_number,
+ bool is_first,
+ bool is_last);
void output (SCM output_channel);
};
{"alias", ALIAS},
{"alternative", ALTERNATIVE},
{"book", BOOK},
+ {"bookpart", BOOKPART},
{"change", CHANGE},
{"chordmode", CHORDMODE},
{"chords", CHORDS},
break_into_pieces (0, end, current_configuration (0));
message (_ ("Computing page breaks..."));
- vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
+ vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1);
Page_spacing_result res = pack_systems_on_least_pages (0, first_page_num);
SCM lines = systems ();
return make_pages (res.systems_per_page_, lines);
{
vsize end = last_break_position ();
vsize max_sys_count = max_system_count (0, end);
- vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
+ vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1);
SCM forced_page_count = book_->paper_->c_variable ("page-count");
set_to_ideal_line_configuration (0, end);
SCM book = book_->self_scm ();
int first_page_number
- = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
+ = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1);
+ bool last_part = ly_scm2bool (book_->paper_->c_variable ("part-is-last"));
SCM ret = SCM_EOL;
- SCM label_page_table = SCM_EOL;
+ SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
+ if (label_page_table == SCM_UNDEFINED)
+ label_page_table = SCM_EOL;
for (vsize i = 0; i < lines_per_page.size (); i++)
{
SCM page_num = scm_from_int (i + first_page_number);
- SCM last = scm_from_bool (i == lines_per_page.size () - 1);
+ SCM last = scm_from_bool (last_part && (i == lines_per_page.size () - 1));
SCM rag = scm_from_bool (ragged () || (to_boolean (last)
&& ragged_last ()));
SCM line_count = scm_from_int (lines_per_page[i]);
ret = scm_cons (page, ret);
systems = scm_list_tail (systems, line_count);
}
- book_->paper_->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
+ book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
ret = scm_reverse (ret);
return ret;
}
if (start > 0 && best.demerits_ < state_[start-1].demerits_)
continue;
- int p_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
+ int p_num = robust_scm2int (book_->paper_->c_variable ("part-first-page-number"), 1);
if (start > 0)
{
/* except possibly for the first page, enforce the fact that first_page_number_
/* this should only actually modify first-page-number if
auto-first-page-number was true. */
- book_->paper_->set_variable (ly_symbol2scm ("first-page-number"),
+ book_->paper_->set_variable (ly_symbol2scm ("part-first-page-number"),
scm_from_int (soln[0].first_page_number_));
return Page_breaking::make_pages (lines_per_page, systems);
}
header_0_ = SCM_EOL;
pages_ = SCM_BOOL_F;
scores_ = SCM_EOL;
+ bookparts_ = SCM_EOL;
performances_ = SCM_EOL;
systems_ = SCM_BOOL_F;
scm_gc_mark (b->pages_);
scm_gc_mark (b->performances_);
scm_gc_mark (b->scores_);
+ scm_gc_mark (b->bookparts_);
return b->systems_;
}
return 1;
}
+Output_def *
+Paper_book::top_paper ()
+{
+ Output_def *paper = paper_;
+ while (paper->parent_)
+ paper = paper->parent_;
+ return paper;
+}
+
SCM
dump_fields ()
{
scores_ = scm_cons (s, scores_);
}
+void
+Paper_book::add_bookpart (SCM p)
+{
+ bookparts_ = scm_cons (p, bookparts_);
+}
+
void
Paper_book::add_performance (SCM s)
{
performances_ = scm_cons (s, performances_);
}
-void
-Paper_book::output (SCM output_channel)
+int
+Paper_book::output_aux (SCM output_channel,
+ int first_page_number,
+ bool is_first,
+ bool is_last)
{
if (scm_is_pair (performances_))
{
scm_call_2 (proc, performances (), output_channel);
}
- if (scores_ == SCM_EOL)
- return;
+ if (scm_is_pair (bookparts_))
+ {
+ bool is_first_part = is_first;
+ int page_number = first_page_number;
+ for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+ if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p)))
+ {
+ bool is_last_part = (is_last && !scm_is_pair (scm_cdr (p)));
+ page_number += pbookpart->output_aux (output_channel,
+ page_number,
+ is_first_part,
+ is_last_part);
+ is_first_part = false;
+ }
+ return page_number;
+ }
+ else
+ {
+ if (scores_ == SCM_EOL)
+ return 0;
+ paper_->set_variable (ly_symbol2scm ("part-first-page-number"),
+ scm_long2num (first_page_number));
+ paper_->set_variable (ly_symbol2scm ("part-is-first"),
+ ly_bool2scm (is_first));
+ paper_->set_variable (ly_symbol2scm ("part-is-last"),
+ ly_bool2scm (is_last));
+ /* Generate all stencils to trigger font loads. */
+ return scm_ilength (pages ());
+ }
+}
- /* Generate all stencils to trigger font loads. */
- pages ();
+void
+Paper_book::output (SCM output_channel)
+{
+ output_aux (output_channel,
+ robust_scm2int (paper_->c_variable ("first-page-number"), 1),
+ true,
+ true);
SCM scopes = SCM_EOL;
if (ly_is_module (header_))
}
void
-Paper_book::classic_output (SCM output)
+Paper_book::classic_output_aux (SCM output)
{
if (scm_is_pair (performances_))
{
/* Generate all stencils to trigger font loads. */
systems ();
+}
+
+void
+Paper_book::classic_output (SCM output)
+{
+ classic_output_aux (output);
SCM scopes = SCM_EOL;
if (ly_is_module (header_))
{
SCM system_specs = SCM_EOL;
- Stencil title = book_title ();
- if (!title.is_empty ())
+ if (ly_scm2bool (paper_->c_variable ("part-is-first")))
{
- SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties"));
- Prob *ps = make_paper_system (props);
- paper_system_set_stencil (ps, title);
-
- system_specs = scm_cons (ps->self_scm (), system_specs);
- ps->unprotect ();
+ Stencil title = book_title ();
+ if (!title.is_empty ())
+ {
+ SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties"));
+ Prob *ps = make_paper_system (props);
+ paper_system_set_stencil (ps, title);
+
+ system_specs = scm_cons (ps->self_scm (), system_specs);
+ ps->unprotect ();
+ }
}
SCM page_properties
return systems_;
systems_ = SCM_EOL;
- SCM specs = get_system_specs ();
- for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
+ if (scm_is_pair (bookparts_))
{
- if (Paper_score *pscore = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
- {
- SCM system_list = scm_vector_to_list (pscore->get_paper_systems ());
- system_list = scm_reverse (system_list);
- systems_ = scm_append (scm_list_2 (system_list, systems_));
- }
- else
- {
- systems_ = scm_cons (scm_car (s), systems_);
- }
+ for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+ if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p)))
+ systems_ = scm_append_x (scm_list_2 (systems_, pbookpart->systems ()));
}
-
- systems_ = scm_reverse (systems_);
-
- /* backwards compatibility for the old page breaker */
- int i = 0;
- Prob *last = 0;
- for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s))
+ else
{
- Prob *ps = unsmob_prob (scm_car (s));
- ps->set_property ("number", scm_from_int (++i));
-
- if (last
- && to_boolean (last->get_property ("is-title"))
- && !scm_is_number (ps->get_property ("penalty")))
- ps->set_property ("penalty", scm_from_int (10000));
- last = ps;
-
- if (scm_is_pair (scm_cdr (s)))
- {
- SCM perm = ps->get_property ("page-break-permission");
- Prob *next = unsmob_prob (scm_cadr (s));
- if (perm == SCM_EOL)
- next->set_property ("penalty", scm_from_int (10001));
- else if (perm == ly_symbol2scm ("force"))
- next->set_property ("penalty", scm_from_int (-10001));
- }
+ SCM specs = get_system_specs ();
+ for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
+ {
+ if (Paper_score *pscore = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
+ {
+ SCM system_list = scm_vector_to_list (pscore->get_paper_systems ());
+ system_list = scm_reverse (system_list);
+ systems_ = scm_append (scm_list_2 (system_list, systems_));
+ }
+ else
+ {
+ systems_ = scm_cons (scm_car (s), systems_);
+ }
+ }
+ systems_ = scm_reverse (systems_);
+
+ /* backwards compatibility for the old page breaker */
+ int i = 0;
+ Prob *last = 0;
+ for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s))
+ {
+ Prob *ps = unsmob_prob (scm_car (s));
+ ps->set_property ("number", scm_from_int (++i));
+
+ if (last
+ && to_boolean (last->get_property ("is-title"))
+ && !scm_is_number (ps->get_property ("penalty")))
+ ps->set_property ("penalty", scm_from_int (10000));
+ last = ps;
+
+ if (scm_is_pair (scm_cdr (s)))
+ {
+ SCM perm = ps->get_property ("page-break-permission");
+ Prob *next = unsmob_prob (scm_cadr (s));
+ if (perm == SCM_EOL)
+ next->set_property ("penalty", scm_from_int (10001));
+ else if (perm == ly_symbol2scm ("force"))
+ next->set_property ("penalty", scm_from_int (-10001));
+ }
+ }
}
return systems_;
return pages_;
pages_ = SCM_EOL;
- SCM proc = paper_->c_variable ("page-breaking-wrapper");
- pages_ = scm_apply_0 (proc, scm_list_1 (self_scm ()));
-
- /* set systems_ from the pages */
- if (systems_ == SCM_BOOL_F)
+ if (scm_is_pair (bookparts_))
{
- systems_ = SCM_EOL;
- for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p))
- {
- Prob *page = unsmob_prob (scm_car (p));
- SCM systems = page->get_property ("lines");
-
- systems_ = scm_append (scm_list_2 (systems_, systems));
- }
+ for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+ if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p)))
+ pages_ = scm_append_x (scm_list_2 (pages_, pbookpart->pages ()));
+ }
+ else
+ {
+ SCM proc = paper_->c_variable ("page-breaking-wrapper");
+ pages_ = scm_apply_0 (proc, scm_list_1 (self_scm ()));
+
+ /* set systems_ from the pages */
+ if (systems_ == SCM_BOOL_F)
+ {
+ systems_ = SCM_EOL;
+ for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p))
+ {
+ Prob *page = unsmob_prob (scm_car (p));
+ SCM systems = page->get_property ("lines");
+ systems_ = scm_append (scm_list_2 (systems_, systems));
+ }
+ }
}
-
return pages_;
}
%token ALIAS "\\alias"
%token ALTERNATIVE "\\alternative"
%token BOOK "\\book"
+%token BOOKPART "\\bookpart"
%token CHANGE "\\change"
%token CHORDMODE "\\chordmode"
%token CHORDS "\\chords"
%type <book> book_block
%type <book> book_body
+%type <book> bookpart_block
+%type <book> bookpart_body
%type <i> bare_unsigned
%type <scm> figured_bass_alteration
scm_call_2 (proc, PARSER->self_scm (), book->self_scm ());
book->unprotect ();
}
+ | bookpart_block {
+ Book *bookpart = $1;
+ SCM proc = PARSER->lexer_->lookup_identifier ("toplevel-bookpart-handler");
+ scm_call_2 (proc, PARSER->self_scm (), bookpart->self_scm ());
+ bookpart->unprotect ();
+ }
| score_block {
Score *score = $1;
$$ = $1->self_scm ();
$1->unprotect ();
}
+ | bookpart_block {
+ $$ = $1->self_scm ();
+ $1->unprotect ();
+ }
| output_def {
$$ = $1->self_scm ();
$1->unprotect ();
$$->paper_ = $2;
$2->unprotect ();
}
+ | book_body bookpart_block {
+ Book *bookpart = $2;
+ SCM proc = PARSER->lexer_->lookup_identifier ("book-bookpart-handler");
+ scm_call_2 (proc, $$->self_scm (), bookpart->self_scm ());
+ bookpart->unprotect ();
+ }
| book_body score_block {
Score *score = $2;
SCM proc = PARSER->lexer_->lookup_identifier ("book-score-handler");
| book_body error {
$$->paper_ = 0;
$$->scores_ = SCM_EOL;
+ $$->bookparts_ = SCM_EOL;
}
| book_body object_id_setting {
$$->user_key_ = ly_scm2string ($2);
}
;
+bookpart_block:
+ BOOKPART '{' bookpart_body '}' {
+ $$ = $3;
+ }
+ ;
+
+bookpart_body:
+ {
+ $$ = new Book;
+ $$->origin ()->set_spot (@$);
+ }
+ | BOOK_IDENTIFIER {
+ $$ = unsmob_book ($1);
+ $$->protect ();
+ $$->origin ()->set_spot (@$);
+ }
+ | bookpart_body paper_block {
+ $$->paper_ = $2;
+ $2->unprotect ();
+ }
+ | bookpart_body score_block {
+ Score *score = $2;
+ SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-score-handler");
+ scm_call_2 (proc, $$->self_scm (), score->self_scm ());
+ score->unprotect ();
+ }
+ | bookpart_body composite_music {
+ Music *music = unsmob_music ($2);
+ SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-music-handler");
+ scm_call_3 (proc, PARSER->self_scm (), $$->self_scm (), music->self_scm ());
+ }
+ | bookpart_body full_markup {
+ SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-text-handler");
+ scm_call_2 (proc, $$->self_scm (), scm_list_1 ($2));
+ }
+ | bookpart_body full_markup_list {
+ SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-text-handler");
+ scm_call_2 (proc, $$->self_scm (), $2);
+ }
+ | bookpart_body lilypond_header {
+ $$->header_ = $2;
+ }
+ | bookpart_body error {
+ $$->paper_ = 0;
+ $$->scores_ = SCM_EOL;
+ }
+ | bookpart_body object_id_setting {
+ $$->user_key_ = ly_scm2string ($2);
+ }
+ ;
+
score_block:
SCORE '{' score_body '}' {
$$ = $3;
#(define musicQuotes (make-hash-table 29))
#(define toplevel-book-handler print-book-with-defaults)
+#(define toplevel-bookpart-handler collect-bookpart-for-book)
#(define toplevel-music-handler collect-music-for-book)
#(define toplevel-score-handler collect-scores-for-book)
#(define toplevel-text-handler collect-scores-for-book)
+#(define book-bookpart-handler ly:book-add-bookpart!)
#(define book-music-handler collect-book-music-for-book)
#(define book-score-handler ly:book-add-score!)
#(define book-text-handler ly:book-add-score!)
+#(define bookpart-score-handler ly:book-add-score!)
+#(define bookpart-text-handler ly:book-add-score!)
+#(define bookpart-music-handler collect-book-music-for-book)
\include "predefined-fretboards-init.ly"
#(ly:set-option 'old-relative #f)
-#(define toplevel-scores '())
+#(define toplevel-scores (list))
+#(define toplevel-bookparts (list))
#(define output-count 0)
#(define $defaultheader #f)
#(define version-seen #f)
(version-not-seen-message input-file-name))
#(ly:set-option 'protected-scheme-parsing #f)
-#(if (or (pair? toplevel-scores) output-empty-score-list)
- ((if (defined? 'default-toplevel-book-handler)
- default-toplevel-book-handler
- toplevel-book-handler)
- parser
- (apply ly:make-book $defaultpaper $defaultheader toplevel-scores)))
+#(let ((book-handler (if (defined? 'default-toplevel-book-handler)
+ default-toplevel-book-handler
+ toplevel-book-handler)))
+ (cond ((pair? toplevel-bookparts)
+ (let ((book (ly:make-book $defaultpaper $defaultheader)))
+ (map (lambda (part)
+ (ly:book-add-bookpart! book part))
+ (reverse! toplevel-bookparts))
+ (set! toplevel-bookparts (list))
+ ;; if scores have been defined after the last explicit \bookpart:
+ (if (pair? toplevel-scores)
+ (map (lambda (score)
+ (ly:book-add-score! book score))
+ (reverse! toplevel-scores)))
+ (set! toplevel-scores (list))
+ (book-handler parser book)))
+ ((or (pair? toplevel-scores) output-empty-score-list)
+ (book-handler parser (apply ly:make-book $defaultpaper
+ $defaultheader toplevel-scores)))))
#(if (eq? expect-error (ly:parser-has-error? parser))
(ly:parser-clear-error parser)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; parser <-> output hooks.
-
+(define-public (collect-bookpart-for-book parser book-part)
+ "Toplevel book-part handler"
+ (define (add-bookpart book-part)
+ (ly:parser-define!
+ parser 'toplevel-bookparts
+ (cons book-part (ly:parser-lookup parser 'toplevel-bookparts))))
+ ;; If toplevel scores have been found before this \bookpart,
+ ;; add them first to a dedicated bookpart
+ (if (pair? (ly:parser-lookup parser 'toplevel-scores))
+ (begin
+ (add-bookpart (ly:make-book-part
+ (ly:parser-lookup parser 'toplevel-scores)))
+ (ly:parser-define! parser 'toplevel-scores (list))))
+ (add-bookpart book-part))
+
(define-public (collect-scores-for-book parser score)
(ly:parser-define!
parser 'toplevel-scores