5

It's in the title. I'm trying to make a command-creating macro which would quickly create a length and setting it to some \settowidth{}{} output, then making it a command for horizontal spacing.

I also tried with \csname#1\endcsname but it doesn't work either.

\documentclass{article}

\newcommand{\newspace}[2]{%
    \newlength{#1aux}%
    \settowidth{#1aux}{#2}%
    \newcommand{#1}{\hspace*{#1aux}}}

\begin{document}
    
\newspace{\QQspace}{QQ} 

    AQQA
    A\QQspace A
    
\end{document}

3 Answers 3

4

The crux of the answer is given in How to define a macro to create a new macro with a name passed as its argument? with the #1aux macro requiring additional \csnames and associated \expandafters to ensure the \csname happens first.

\newcommand{\newspace}[2]{%
    \expandafter\newlength\expandafter{\csname#1aux\endcsname}%
    \expandafter\settowidth\expandafter{\csname#1aux\endcsname}{#2}%
    \expandafter\newcommand\expandafter{\csname#1\endcsname}{%
        \expandafter\hspace\expandafter*\expandafter{\csname#1aux\endcsname}}}

However with the aid of the calc package, \widthof circumvents a lot of unpleasant boilerplate code

\newcommand{\betternewspace}[2]{%
    \expandafter\newcommand\expandafter{\csname#1\endcsname}{\hspace*{\widthof{#2}}}}

\hphantom{#2} (which doesn't require calc) has a similar effect to \hspace*{\widthof{#2}} but acts as \hspace rather than \hspace*.

\documentclass{article}
\usepackage{calc}

\newcommand{\newspace}[2]{%
    \expandafter\newlength\expandafter{\csname#1aux\endcsname}%
    \expandafter\settowidth\expandafter{\csname#1aux\endcsname}{#2}%
    \expandafter\newcommand\expandafter{\csname#1\endcsname}{\expandafter\hspace\expandafter*\expandafter{\csname#1aux\endcsname}}}
 
\newcommand{\betternewspace}[2]{%
    \expandafter\newcommand\expandafter{\csname#1\endcsname}{\hspace*{\widthof{#2}}}}

\begin{document}
    
\newspace{QQspace}{QQ} 
\betternewspace{QQspaceTwo}{QQ} 
\noindent%
AQQA\\
A\QQspace B\\
A\QQspaceTwo B\\
\end{document}

Compiled code showing AQQA on one line and a gap equal to QQ between A and B on the second and third lines

1
  • 1
    You're trying to create two distinct macros from a single macro, if #1 is a macro then \newlength{#1aux} is just going to create a length equal to #1 (and then do something undesirable with the remaining tokens), to generate a new macro name you'll have to use \csname to append the aux and you could work around that with \expandafter\string\@gobble as in this answer but that seems to make life more difficult not less.
    – Dai Bowen
    Apr 25 at 1:44
6

You don't need to allocate a length: just define \QQspace to \hspace*{<width>}, where the width can be computed using a scratch length.

\documentclass{article}

\makeatletter
\newcommand{\newspace}[2]{%
  \settowidth{\dimen@}{#2}%
  \ExpandArgs{ne}\newcommand{#1}{\noexpand\hspace*{\the\dimen@}}%
}
\makeatother

\begin{document}

\newspace{\QQspace}{QQ}

AQQA

A\QQspace A

\texttt{\meaning\QQspace}

\end{document}

This uses \ExpandArgs{ne} that

  1. jumps over the next token, here \newcommand;
  2. jumps over the next braced argument, because of n, here {#1};
  3. fully expands the contents of the next braced argument.

This explains the \noexpand in front of \hspace and \the in front of \dimen@.

enter image description here

With “classic” code, the \ExpandArgs line might be

\begingroup\edef\x{\endgroup
  \noexpand\newcommand{\noexpand#1}{\noexpand\hspace*{\the\dimen@}}%
}\x
1

Here is a solution based on Dai Bowen's answer, but restablishing the backslash in the argument.

Credit: Martin Scharrer.

\documentclass{article}
\usepackage{calc} % Provides the useful \widthof command.

\makeatletter % Makes the character "@" a normal letter (here needed to call the \@gobble macro).

\newcommand{\newspace}[2]{%
\expandafter\newcommand\csname\expandafter\@gobble\string#1\endcsname{%
\hspace*{\widthof{#2}}%
                        }%
}

\makeatother % Resets @'s catcode to default.

\begin{document}
    
    \newspace{\QQspace}{QQ} 
    
    AQQA

    A\QQspace A

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .