%Lyluatex LaTeX style. % % Copyright (C) 2015-2023 jperon and others (see CONTRIBUTORS.md) % License: MIT % This file is part of lyluatex. \NeedsTeXFormat{LaTeX2e}% \ProvidesPackage{lyluatex}[2023/04/18 v1.1.5] %%LYLUATEX_DATE LYLUATEX_VERSION % Dependencies \RequirePackage{graphicx} \RequirePackage{minibox} \RequirePackage{environ} \RequirePackage{currfile} \RequirePackage{pdfpages} \IfFileExists{varwidth.sty}{\RequirePackage{varwidth}}{} \RequirePackage{luaoptions} \RequirePackage{metalogo} \newcommand{\lyluatex}{\textit{ly}\LuaTeX} \edef\ly@false{false}\def\ly@istwosided{\if@twoside\else\ly@false\fi} \savecatcodetable 40 % Copied from ifnextok.sty. % We use \providecommand instead of \newcommand and \def in order % to avoid overriding ifnextok if it is already loaded. \providecommand{\IfNextToken}[3]{% \let\nextok@match= #1% \def\nextok@if{#2}\def\nextok@else{#3}% \futurelet\@let@token\nextok@decide% } \providecommand\nextok@decide{% \ifx\@let@token\nextok@match \expandafter\nextok@if \else \expandafter\nextok@else \fi% } % Options \catcode`-=11 \directlua{ local _opt = lua_options lua_options.register('ly', { ['addversion'] = {'false', 'true', ''}, ['autoindent'] = {'true', 'false', ''}, ['cleantmp'] = {'false', 'true', ''}, ['currfiledir'] = {}, ['debug'] = {'false', 'true', ''}, ['extra-bottom-margin'] = {'0', _opt.is_dim}, ['extra-top-margin'] = {'0', _opt.is_dim}, ['fix_badly_cropped_staffgroup_brackets'] = {'false', 'true', ''}, ['nofix_badly_cropped_staffgroup_brackets'] = {'default', _opt.is_neg}, ['force-compilation'] = {'false', 'true', ''}, ['fragment'] = {'', 'false', 'true'}, ['nofragment'] = {'default', _opt.is_neg}, ['fullpagealign'] = {'crop', 'staffline'}, ['fullpagestyle'] = {''}, ['gutter'] = {'.4in', _opt.is_dim}, ['exampleindent'] = {'gutter', _opt.is_alias}, ['leftgutter'] = {'', _opt.is_dim}, ['rightgutter'] = {'', _opt.is_dim}, ['hpadding'] = {'0.75ex', _opt.is_dim}, ['include_after_body'] = {'false'}, ['include_before_body'] = {'false'}, ['include_footer'] = {'false'}, ['include_header'] = {'false'}, ['includepaths'] = {'./'}, ['indent'] = {'', _opt.is_dim}, ['noindent'] = {'default', _opt.is_neg}, ['insert'] = {'', 'systems', 'fullpage', 'inline', 'bare-inline'}, ['intertext'] = {''}, ['label'] = {'false'}, ['labelprefix'] = {'ly_'}, ['line-width'] = {[[\linewidth]], _opt.is_dim}, ['ly-version'] = {'2.18.2'}, ['max-protrusion'] = {[[\maxdimen]], _opt.is_dim}, ['max-left-protrusion'] = {'', _opt.is_dim}, ['max-right-protrusion'] = {'', _opt.is_dim}, ['noclef'] = {'false', 'true', ''}, ['nostaff'] = {'false', 'true', ''}, ['nostaffsymbol'] = {'false', 'true', ''}, ['notime'] = {'false', 'true', ''}, ['notiming'] = {'false', 'true', ''}, ['notimesig'] = {'false', 'true', ''}, ['optimize-pdf'] = {'false', 'true', ''}, ['paperwidth'] = {[[\paperwidth]], _opt.is_dim}, ['paperheight'] = {[[\paperheight]], _opt.is_dim}, ['papersize'] = {'false'}, ['pass-fonts'] = {'false', 'true', ''}, ['current-font'] = {}, ['current-font-as-main'] = {'false', 'true', ''}, ['rmfamily'] = {}, ['sffamily'] = {}, ['ttfamily'] = {}, ['print-page-number'] = {'false', 'true', ''}, ['first-page-number'] = {'false', ''}, ['print-first-page-number'] = {'true', 'false', ''}, ['print-only'] = {''}, ['do-not-print'] = {''}, ['printfilename'] = {'false', 'true', ''}, ['program'] = {'lilypond'}, ['protrusion'] = {'', _opt.is_dim}, ['noprotrusion'] = {'default', _opt.is_neg}, ['raw-pdf'] = {'false', 'true', ''}, ['quote'] = {'false', 'true', ''}, ['ragged-right'] = {'default', 'true', 'false', ''}, ['noragged-right'] = {'default', _opt.is_neg}, ['relative'] = {'false', _opt.is_num}, ['norelative'] = {'default', _opt.is_neg}, ['showfailed'] = {'false', 'true' ,''}, ['staffsize'] = {'0', _opt.is_dim}, ['inline-staffsize'] = {'0', _opt.is_dim}, ['system-count'] = {'0', _opt.is_dim}, ['tmpdir'] = {'tmp-ly'}, ['twoside'] = {'\ly@istwosided', 'false', 'true', ''}, ['verbatim'] = {'false', 'true', ''}, ['voffset'] = {'0pt', _opt.is_dim}, ['valign'] = {'center', 'top', 'bottom'}, ['write-headers'] = {'false'}, % MusicXML options ['absolute'] = {'false', 'true', ''}, ['language'] = {'false'}, ['lxml'] = {'false', 'true'}, ['no-articulation-directions'] = {'true', 'false', ''}, ['no-beaming'] = {'true', 'false', ''}, ['no-page-layout'] = {'true', 'false', ''}, ['no-rest-positions'] = {'true', 'false', ''}, ['verbose'] = {'false', 'true', ''}, ['xml2ly'] = {'musicxml2ly'}, }) } \directlua{ ly = require(kpse.find_file("lyluatex.lua") or "lyluatex.lua") ly.make_list_file() if lua_options.client('ly').cleantmp then luatexbase.add_to_callback('stop_run', ly.clean_tmp_dir, 'lyluatex cleantmp') luatexbase.add_to_callback('stop_run', ly.conclusion_text, 'lyluatex conclusion') end } \catcode`-=12 %\directlua{ly.TWOSIDE = 'f'} \newcommand{\ly@setunits}{% \let\ly@old@in\in\protected\def\in{in}% \let\ly@old@pt\pt\protected\def\pt{pt}% \let\ly@old@mm\mm\protected\def\mm{mm}% \let\ly@old@cm\cm\protected\def\cm{cm}% \let\ly@old@hfuzz\hfuzz\setlength{\hfuzz}{\maxdimen}% } \newcommand{\ly@resetunits}{% \let\in\ly@old@in% \let\pt\ly@old@pt% \let\mm\ly@old@mm% \let\cm\ly@old@cm% \setlength{\hfuzz}{\ly@old@hfuzz}% } % How the filename of a score will look like (if printed) \newcommand{\lyFilename}[1]{\noindent #1\par\bigskip} % Appearance of verbatim 'intertext' (if printed) \newcommand{\lyIntertext}[1]{\noindent #1\par\bigskip} % Appearance of LilyPond version (if printed) \newcommand{\lyVersion}[1]{\noindent {\footnotesize\emph{(GNU LilyPond #1)}\par}\bigskip} % Retrieve the three main font families (rm, sf, tt) % and store them as options. Additionally store the % *current* font for optional use. \newcommand{\ly@currentfonts}{% \begingroup% \setluaoption{ly}{current-font}{% \directlua{ly.get_font_family(font.current())} } \rmfamily \edef\rmfamilyid{\fontid\font}% \sffamily \edef\sffamilyid{\fontid\font}% \ttfamily \edef\ttfamilyid{\fontid\font}% % Set font families to those of the document % that haven't been set explicitly as options. \directlua{ly.set_fonts(\rmfamilyid, \sffamilyid, \ttfamilyid)}% \endgroup% } % Main commands % Score processing \newcommand*{\ly@compilescore}[1]{% \ly@setunits% \setluaoption{ly}{currfiledir}{\currfiledir} \setluaoption{ly}{twoside}{\ly@istwosided} \directlua{ #1 ly.newpage_if_fullpage() }% \ly@resetunits% \ly@currentfonts% \directlua{ly.score:process()}% } % Inclusion of a .ly file \newcommand*\includely[2][]{% \directlua{ly.state = 'file'}% \ly@compilescore{ly.file( '\luatexluaescapestring{#2}', [[#1]] )}% } % Inclusion of a musicxml file \newcommand*\musicxmlfile[2][]{% \directlua{ly.state = 'file'}% \ly@compilescore{ly.file_musicxml( '\luatexluaescapestring{#2}', [[#1]] )} } % Base environments to include a LilyPond fragment integrated into % the document. \newcommand\lyscorebegin{\directlua{ly.buffenv_begin()}} \newcommand\lyscoreend{\directlua{ly.buffenv_end()}} \newenvironment{ly@bufferenv}{% \directlua{ ly.insert_inline = string.match([[\options]], 'insert.*inline') if ly.insert_inline then if ly.varwidth_available then tex.print([[ \string\begin{varwidth}{\string\linewidth} ]]) else ly.insert_inline = false ly.err( [[You have required 'insert=inline' with lilypond environment, but package 'varwidth' wasn't found; either install it, or disable this option.]] ) end end } \lyscorebegin% }{% \lyscoreend% \ly@compilescore{ly.fragment(ly.score_content, [[\options]])}% \hspace{0pt}\\ \directlua{ if ly.insert_inline then tex.print([[\string\end{varwidth}]]) end }% } \NewEnviron{ly@compilely}{% \ly@compilescore{ly.fragment( '\luatexluaescapestring{\unexpanded\expandafter{\BODY}}', [[\options]] )}% } % Commands to print verbatim content of the score \newcommand\lysetverbenv[2]{% \directlua{ly.verbenv = { '\luatexluaescapestring{\detokenize{#1}}', '\luatexluaescapestring{\detokenize{#2}}' }}% } % Environments to record custom headers and footers to be included in fragments \newenvironment{lysavefrag}[1]{% \edef\filename{#1} \lyscorebegin% }{% \lyscoreend% \directlua{ly.write_to_file('\filename'..'.ly', table.concat(ly.score_content,'\string\n'))}% } % Commands to transform or define lilypond environments so that it isn't necessary to add empty []. \def\lyenv#1{% \expandafter\let\csname ly@env@#1\expandafter\endcsname\csname #1\endcsname% \expandafter\let\csname ly@env@end#1\expandafter\endcsname\csname end#1\endcsname% \expandafter\def\csname #1\endcsname{\IfNextToken[{\csname ly@env@#1\endcsname}{\csname ly@env@#1\endcsname[]}}% } \long\def\lynewenvironment#1{\@ifnextchar[{\ly@newenv@a{#1}}{\ly@newenv@a{#1}[0]}} \long\def\ly@newenv@a#1[#2]{\@ifnextchar[{\ly@newenv@b{#1}{#2}}{\ly@newenv@b{#1}{#2}[]}} \long\def\ly@newenv@b#1#2[#3]#4#5{% \newenvironment{#1}[#2][#3]{#4}{#5} \lyenv{#1} } % Parametrized command and environment for included LilyPond fragment \lynewenvironment{ly}[1][noarg]{% \edef\options{#1}% \directlua{ly.state = 'env'}% \ly@bufferenv% }{% \endly@bufferenv% } \newcommand{\lily}[2][]{% \edef\options{#1}% \let\ly@oldrepeat\repeat\def\repeat{}% Fix #51 \directlua{ly.state = 'cmd'}% \begin{ly@compilely}% #2 \end{ly@compilely}% \let\repeat\ly@oldrepeat% } \newcommand{\lyscore}[1]{\directlua{ local i = tonumber('#1') or '#1' if i == '' then i = 1 end tex.sprint(ly.score[i] or '') }} % Commands for compatibility with lilypond-book \let\lilypondfile\includely% \protected\def\lilypond{% \def\reserved@a{lilypond}% \ifx\reserved@a\@currenvir\expandafter\ly% \else\expandafter\lily\fi% }% \let\endlilypond\endly