Automatically formatting mesostics
Disclaimer. The code below doesn't imply in any way whatsoever that I endorse or otherwise hold in esteem any aspect of John Cage's work.
The following approach splits the input at \\
, then builds lines one by one, setting an \hbox
where the width of the center letter is measured; the box will then consist of
- a box as wide as half the linewidth minus half the center letter's width, flush right;
- the center letter;
- a box like in step 1, but flush left.
\documentclass{article}
\usepackage{environ,xparse}
\usepackage{kantlipsum} % for context
\ExplSyntaxOn
\NewEnviron{mesostic}
{
\par\addvspace{\topsep}
\mesostic_build:V \BODY
\addvspace{\topsep}
}
\seq_new:N \l__mesostic_body_seq
\box_new:N \l__mesostic_center_box
\cs_new_protected:Nn \mesostic_build:n
{
\seq_set_split:Nnn \l__mesostic_body_seq { \\ } { #1 }
\seq_map_inline:Nn \l__mesostic_body_seq
{
\__mesostic_line:w ##1 \q_stop
}
}
\cs_generate_variant:Nn \mesostic_build:n { V }
\cs_new_protected:Npn \__mesostic_line:w #1 | #2 | #3 \q_stop
{
\hbox_set:Nn \l__mesostic_center_box { \textbf{#2} }
\hbox_to_wd:nn { \linewidth }
{
\hbox_to_wd:nn { (\linewidth-\box_wd:N \l__mesostic_center_box)/2 }
{
\hss #1
}
\textbf{#2}
\hbox_to_wd:nn { (\linewidth-\box_wd:N \l__mesostic_center_box)/2 }
{
#3 \hss
}
}
}
\ExplSyntaxOff
\begin{document}
\kant[1]
\begin{mesostic}
near|L|y napping, \\
cam|E| a \\
tappi|N|g, \\
as |O|f \\
gently |R|apping, \\
at my chamb|E|r door.
\end{mesostic}
\kant[2]
\end{document}
Changing the font might be implemented by making a tentative typesetting and measuring each part in order to see whether it satisfies the constraints of being contained in the line width; in case of failure, stop, change the font size and repeat.
A variant that allows for an optional argument where to state a font or a font size (or both); also a check for a trailing \\
is added. The main code has been simplified (thanks to jfbu for the idea).
\documentclass{article}
\usepackage{environ,xparse}
\usepackage{kantlipsum} % for context
\ExplSyntaxOn
\NewEnviron{mesostic}[1][]
{
#1
\par\addvspace{\topsep}
\mesostic_build:V \BODY
\addvspace{\topsep}
}
\seq_new:N \l__mesostic_body_seq
\cs_generate_variant:Nn \tl_if_empty:nT { x }
\cs_new_protected:Nn \mesostic_build:n
{
\seq_set_split:Nnn \l__mesostic_body_seq { \\ } { #1 }
% check for a trailing \\
\tl_if_empty:xT { \seq_item:Nn \l__mesostic_body_seq { -1 } }
{
\seq_pop_right:NN \l__mesostic_body_seq \l_tmpa_tl
}
\seq_map_inline:Nn \l__mesostic_body_seq
{
\__mesostic_line:w ##1 \q_stop
}
}
\cs_generate_variant:Nn \mesostic_build:n { V }
\cs_new_protected:Npn \__mesostic_line:w #1 | #2 | #3 \q_stop
{
\hbox_to_wd:nn { \linewidth }
{
\hss
\hbox_to_wd:nn { 0pt } { \hss \tl_lower_case:n { #1 } }
\textbf{\tl_upper_case:n { #2 }}
\hbox_to_wd:nn { 0pt } { \tl_lower_case:n { #3 } \hss }
\hss
}
}
\ExplSyntaxOff
\begin{document}
\kant[1]
\begin{mesostic}
near|L|y napping, \\
cam|E| a \\
tappi|N|g, \\
as |O|f \\
gently |R|apping, \\
at my chamb|E|r door.
\end{mesostic}
\kant[2]
\begin{mesostic}[\sffamily\footnotesize]
NEAR|l|Y NAPPING \\
CAM|e| A \\
TAPPI|n|G \\
AS |o|F \\
GENTLY |r|APPING \\
AT MY CHAMB|e|R DOOR \\
\end{mesostic}
\kant[3]
\end{document}
\documentclass{article}
\makeatletter
\def\mesostic@end{\end{mesostic}}
\begingroup\catcode`\^^M\active
\gdef\mesostic@aux#1|#2|#3\mesostic@aux%
{\noindent\hfill%
\llap{\MakeLowercase{#1}}%
\textbf{\MakeUppercase{#2}}%
\rlap{\MakeLowercase{#3}}%
\hfill\hbox{}\par%
\expandafter^^M}%
\endgroup
\newenvironment{mesostic}{\parskip0pt\relax
\obeylines
\begingroup\lccode`~`\^^M
\lowercase{\endgroup\def~##1~}{%
\def\mesostic@tmp{##1}%
\ifx\mesostic@tmp\mesostic@end
\expandafter\mesostic@end
\else
\mesostic@aux##1\mesostic@aux
\fi}%
}{}
\makeatother
\begin{document}
blah blah blah
\noindent X\dotfill X
\begin{mesostic}
near|L|y napping,
cam|E| a
tappi|N|g,
as |O|f
gently |R|apping,
at my chamb|E|r door.
\end{mesostic}
\noindent X\dotfill X
blah blah blah
\noindent X\dotfill X
\begin{mesostic}
NEAR|l|Y NAPPING,
CAM|e| A
TAPPI|n|G,
AS |o|F
GENTLY |r|APPING,
AT MY CHAMB|e|R DOOR.
\end{mesostic}
\noindent X\dotfill X
blah blah blah
\end{document}
And using X\dotfill X\dotfill X
for the extra lines for context:
\documentclass{article}
\makeatletter
\let\zzfont\textbf
{\obeylines\everyeof{\noexpand}%
\gdef\zzz#1{%
\catcode`#1\active\scantokens{\def\zzzz{\gdef#1}}%
\zzzz##1^^M{\makebox[.5\textwidth][l]{\zzfont{\string#1}##1}\par}%
}}
\def\zz{\flushright\obeylines%
\let\or\zzz\@Alph{0\fi\iftrue}}%
\def\endzz{\endflushright}
\begin{document}
\begin{zz}
nearLy napping,
camE a
tappiNg,
as Of
gently Rapping,
at my chambEr door.
\end{zz}
\renewcommand\zzfont[1]{\large$\mathcal{#1}$}
\begin{zz}
nearLy napping,
camE a
tappiNg,
as Of
gently Rapping,
at my chambEr door.
\end{zz}
\end{document}