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

  1. a box as wide as half the linewidth minus half the center letter's width, flush right;
  2. the center letter;
  3. 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}

enter image description here

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}

enter image description here


\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}

enter image description here

And using X\dotfill X\dotfill X for the extra lines for context:

enter image description here


enter image description here

 \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}