Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm trying to write a \spaced macro: it takes a string as parameter, decompose that string and then recompose it spreading avery token from the others according to a given \spreadratio. Here are the macro along with an MWE:

\catcode`\@=11

\font\sc="Latin Modern Roman Caps:mapping=tex-text,+onum"

\chardef\box@temp@la=0
\dimendef\dimen@temp@la=0
\dimendef\dimen@temp@lb=2
\toksdef\toks@temp@ga=1

% \boxit is only aimed to highlight the problem.
% If you wanna see the MWE without boxing just comment this
% definition and uncomment the following one.
\def\boxit#1{\vbox{\hrule\hbox{\vrule#1\vrule}\hrule}}
%\def\boxit#1{#1}

\newcount\spreadratio \spreadratio=100

% The interface of \spaced is the following:
%
%    \spaced[<number>]{<token list>}
%
% where the optional parameter is the amount of \spreadratio
% other than the predefined one.
\def\spaced{\futurelet\firsttok\@spaced}

\def\@spaced{%
  \if\firsttok[\let\next\@paramspaced
  \else\let\next\@simplespaced\fi
  \next}

\def\@paramspaced[#1]#2{{\spreadratio=#1\dosp@ced{#2}}}

\def\@simplespaced#1{\dosp@ced{#1}}

\def\dosp@ced#1{{\setbox\box@temp@la\hbox{#1}%
  % the size of the \hbox is changed according
  % to the value of \spreadratio
  \dimen@temp@la\wd\box@temp@la \dimen@temp@lb\dimen@temp@la
  \divide\dimen@temp@lb by\@m
  \multiply\dimen@temp@lb by\spreadratio
  \advance\dimen@temp@la by\dimen@temp@lb
  \global\toks@temp@ga={}%
  \@split{#1}%
  \setbox\box@temp@la\hbox to\dimen@temp@la{\the\toks@temp@ga}%
  \box\box@temp@la}}

\def\@split#1{\@@split#1\end}

\def\@@split#1{%
  \ifx#1\end
    \global\toks@temp@ga=\expandafter{\the\toks@temp@ga\unskip}%
    \let\next\relax
  \else
    \global\toks@temp@ga=\expandafter{\the\toks@temp@ga#1\hfil}%
    \let\next\@@split\fi
  \next}

\catcode`\@=12

\noindent
\boxit{The music}\par\noindent
\boxit{\spaced{The music of Steve Reich}}\par\noindent
\boxit{\spaced[300]{The music of Steve Reich}}\par\noindent
\boxit{{\sc The music of Steve Reich}}\par\noindent
\boxit{\spaced{\sc The music of Steve Reich}}\par\noindent
\boxit{\spaced[300]{\sc The music of Steve Reich}}\par\noindent
% Note that here are no spaces between '\it' and the word 'The'.
\boxit{{\it{}The music of Steve Reich}}\par\noindent
\boxit{\spaced{\it{}The music of Steve Reich}}\par\noindent
\boxit{\spaced[300]{\it{}The music of Steve Reich}}\par\noindent
\boxit{\spaced{The music of Steve Reich}}\par\noindent
\end

The result is the following. enter image description here

As you can see (note the space before the word 'the') when the first token of the mandatory parameter is a macro (just like \sc or \it), \spaced adds a kind of spurious space before the second token.

I can't imagine where that space comes from, and I'm not able to eliminate it.

Where can be my fault?

share|improve this question
    
It seems you want something at least similar to the soul package. Look up that code and you might find an answer. –  Toscho Apr 20 '13 at 9:59
    
@Toscho yes, but above all I would like to understand where I went wrong without reading one thousand of lines or so. –  Jean Baldraque Apr 20 '13 at 10:12
    
With \spaced{\sc A b} the token register is loaded with \sc \hfil A\hfil b\hfil \unskip because you add \hfil after the token no matter what the token is; and spaces disappear, but you probably already knew it. –  egreg Apr 20 '13 at 10:18

2 Answers 2

Your splitting routine doesn't distinguish between letters and commands, so if you try \spaced{\sc A b} the final token list stored in \toks@temp@ga is

\sc \hfil A\hfil b\hfil \unskip

as you can see by adding \showthe\toks@temp@ga to your macros after \let\next\relax.

Of course, the splitting routine also gobbles spaces.

A different strategy is to use XeTeX features.

\catcode`\@=11

\font\rm="Latin Modern Roman:mapping=tex-text,+onum" \rm
\font\sc="Latin Modern Roman Caps:mapping=tex-text,+onum"

\def\spaced{\futurelet\next\@spaced}
\def\@spaced{%
  \ifx\next[%
    \expandafter\@spacedopt
  \else
    \expandafter\@spacednonopt
  \fi}
\def\@spacednonopt#1{#1}
\def\@spacedopt[#1]#2{\begingroup\@addtofont{letterspace=#1}#2\endgroup}
\def\@getfontname{\expandafter\@removequotes\fontname\font}
\def\@removequotes"#1"{#1}
\def\@addtofont#1{%
  \begingroup\edef\x{\endgroup
    \font\noexpand\@temp="\expandafter\@removequotes\fontname\font;#1;"%
    \noexpand\@temp}\x}
\catcode`@=12

\spaced[10]{The music of Bach} This is not spaced

\sc\spaced[10]{The music of Bach} This is not spaced
\bye

enter image description here

share|improve this answer
    
It's a good solution, but has some drawbacks: 1) it works only with XeTeX (and LuaTeX?), as far as it uses an Open Type feature; 2) It leave the original parameterization feature, as far as the letterspace Open Type mechanism is a bit strange (letterspace=x where the spreading is x/S with S=fontsize). I'm trying to implement \spaced in plain TeX, but it seems very difficult to determine where to expand a parameter and where not. –  Jean Baldraque Apr 20 '13 at 13:33

@egreg says:

Your splitting routine doesn't distinguish between letters and commands, so if you try \spaced{\sc A b} the final token list stored in \toks@temp@ga is

\sc \hfil A\hfil b\hfil \unskip

as you can see by adding \showthe\toks@temp@ga to your macros after \let\next\relax.

Well, according to this explanation (and my concerns about parameterization of the macro) I've changed the splitting routine in the following way

\def\@@split#1{%
  \ifx#1\end
    \global\toks@temp@ga=\expandafter{\the\toks@temp@ga\unskip}%
    \let\next\relax
  \else
    % here the routine should dinstiguish
    % between letters and commands
    %
    \ifcat\noexpand#1\relax
      \global\toks@temp@ga=\expandafter{\the\toks@temp@ga#1}%
      \let\next\@@split
    %
    % %%%
    \else
      \global\toks@temp@ga=\expandafter{\the\toks@temp@ga#1\hfil}%
      \let\next\@@split\fi\fi
  \next}

It seems to work properly, but if egreg did not suggest this system there must be a problem.

Is it only a sense of insecurity, or a subtle bug is hidden into the code?

share|improve this answer
2  
I removed my comments. You're using the wrong tool: no letter spacing command can work if you first don't take care of spaces between words. –  egreg Apr 21 '13 at 10:24

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.