1

Short: Is there a way to prevent \xspace from inserting white space if it is at the beginning of a line?

Long: I have defined several formatting macros for use in normal text. One of these (\indoubt) is normally used inside of text to insert annotations. In the normal context, there should be just one space between the preceding word and the output of this macro, so I used \unskip\xspace at the beginning of this macro. However, I also want to display a list of all formatting macros that are actually used in the document -- using the same macro to output some sample text. (I could manually write this text without \xspace, but that is error prone because I would have to remember to change the example text if I ever change the formatting in the macro.) In this list, \xspace is right at the beginning of the line. Is there a way to get rid of it in this place?

Here is an MWE:

\documentclass{article}

\usepackage{xspace}
\usepackage{xifthen}
\usepackage{etoolbox}

\makeatletter
\newcommand\addmacro[1]{%
    \write\@auxout{\noexpand\@writefile{macros}{#1\newline}}%
}
\newcommand\printmacros{%
    \section*{Meaning of formats}%
    \@starttoc{macros}%
}
\makeatother

% Once a formatting macro has been used, set the corresponding flag to TRUE
% and write self-formatted explanation to legend
\newcommand{\checkflag}[2]{%
    \providebool{flag#1}%
    \ifbool{flag#1}
        {}
        {\global\booltrue{flag#1}%
         \addmacro{#2}%
        }%
}

% Express doubt if unsure about a word in the text
\newcommand{\indoubt}[1]{%
    \checkflag{indoubt}{\protect\indoubt{Macro with leading xspace}}%
    \ifthenelse{\equal{#1}{}}
        {\unskip{\textbf{\xspace[?]\xspace}}}
        {\unskip{\textbf{\xspace[#1]\xspace}}}%
    }

\newcommand{\simple}[1]{%
    \checkflag{simple}{\simple{Just a plain formatting directive.}}%
    \textsc{#1\xspace}%
}

\setlength{\parindent}{0pt}

\begin{document}
\printmacros
\section{Test}
This is some textt\indoubt{Wrong spelling?}~\dots \simple{More text.}
\end{document}
Andreas
  • 955
  • What's the reason for so much braces and for \xspace[? – egreg Oct 18 '17 at 17:16
  • The opinion of the package author (not me): Don't use \xspace. My opinion: Don't use \xspace especially not in this context. Preceding a macro with \xspace just seems wrong to me. Just leave a space between the macro (\indoubt) and the preceding word. – Skillmon Oct 18 '17 at 17:19
  • 2
    Insert the space with some command (\myoptionalspace) and redefine this command in your \printmacros command to do nothing. – Ulrike Fischer Oct 18 '17 at 17:21
  • @egreg In this case, "[…]" is not meant as an argument to \xspace! I just want to annotate some words in the text, like this: "This is a sonett [looks German -- in English it's spelled 'sonnet'.] by Shakespeare.", with braces marking the insertions as not belonging to the original. – Andreas Oct 18 '17 at 17:23
  • @Andreas \xspace[ just makes TeX spin its wheels for doing nothing useful. – egreg Oct 18 '17 at 17:25
  • @Andreas then insert it like this: "This is a sonett \indoubt{looks German} by Shakespeare" and remove the xspace from your code. – Skillmon Oct 18 '17 at 17:25
  • There's no place where \xspace does anything useful in your code. Just remove it. And remove the useless braces (although not really harmful). – egreg Oct 18 '17 at 17:27
  • @egreg (if you mean the brackets, they are wanted as the output, just in case you meant them) – Skillmon Oct 18 '17 at 17:28
  • @egreg I now see what you mean! In my actual work, I used \color to highlight the inserted text. In order to keep that color change to just that insertion I inserted the text in extra braces. So you're right, they are quite pointless in this example. Got to leave now, though, so I'll get back to the other comments later on. :-) – Andreas Oct 18 '17 at 17:33
  • 1
    there should never be a macro "with a leading xspace" the only possible place xspace has any use at all is the very last token of a macro definition, fro a macro with no arguments. – David Carlisle Oct 18 '17 at 18:01
  • @UlrikeFischer Thanks, that seems to be the way to go here! – Andreas Oct 19 '17 at 10:36
  • @Skillmon My reasoning for inserting a space at the beginning of the macro was to have a safety net for documents where the macro is called sometimes with and sometimes without a preceding space. I guess \unskip~ would have the same effect because in my macro definition I already know what character will be the next one ([). However, I opted for \xspace because its ability to insert a space only on certain conditions appealed to me -- and because I believed it could somehow be convinced to behave in a special way at the start of a line. – Andreas Oct 19 '17 at 10:59
  • @Skillmon Further, callling the macro immediately after the word to be annotated seems to make sense on a semantic level: The macro is not just anything that appears in the text, but is tied to the preceding word semantically (even though separated in the output) -- the macro output would be quite meaningless if the word was not in the text. So, if I write something like word\indoubt{} and I later on decide to delete this word, I will be less likely to forget to also remove the annotation. In this way, the macro \indoubt{} would be similar to \footnote{}. – Andreas Oct 19 '17 at 11:15
  • @egreg Regarding "\xspace[ just makes TeX spin its wheels for doing nothing useful": Is that because of the unnecessary call of \xspace (which could be replaced by a simple ~), or is it the combination with [ that causes the "spinning wheels"? In the latter case, I guess that would be because [ could be interpreted as an optional argument. But then, wouldn't it also be a problem to write [ after any command if you just want to output the character [? – Andreas Oct 19 '17 at 11:34
  • @Andreas \xspace was meant to be at the trailing position in a parameterless macro. It's completely useless elsewhere (or even harmful). – egreg Oct 19 '17 at 11:58
  • @egreg Thanks, I think I understand you now. :-) In other words: Use \xspace at the end of a macro definition and just a space or \space (which are synonymous by default) at the beginning or in the middle of a macro definition to insert a space unless it would be at the start of a line. – Andreas Oct 19 '17 at 12:53

1 Answers1

4

The point of \xspace even if you decide to ignore its drawbacks is to add space after a command with no arguments, if the command is not followed by punctuation.

It is no use at all with a command with arguments because

 blah blah \foo{argument} blah

the space after \foo{argument} unlike the space after \foo is just a normal space and appears in the output with no special handling.

Using the \xspace command at any place other than the last token of a definition never does anything useful as in such a case you always know what the next token is so the lookahead and testing that xspace does is not useful. {\xspace[... is just a slow way to do { [...

I'm not totally sure what you wanted, but perhaps

\documentclass{article}

\usepackage{xifthen}
\usepackage{etoolbox}

\makeatletter
\newcommand\addmacro[1]{%
    \write\@auxout{\noexpand\@writefile{macros}{#1\par}}%\newline is badness10000 "infinitely bad"
}
\newcommand\printmacros{%
    \section*{Meaning of formats}%
    \@starttoc{macros}%
}
\makeatother

% Once a formatting macro has been used, set the corresponding flag to TRUE
% and write self-formatted explanation to legend
\newcommand{\checkflag}[2]{%
    \providebool{flag#1}%
    \ifbool{flag#1}%
        {}%
        {\global\booltrue{flag#1}%
         \addmacro{#2}%
        }%
}

% Express doubt if unsure about a word in the text
\newcommand{\indoubt}[1]{%
    \ifhmode\unskip\space\fi
    \checkflag{indoubt}{\protect\indoubt{Macro with leading xspace}}%
    \ifthenelse{\equal{#1}{}}%
        {\textbf{[?]}}%
        {\textbf{[#1]}}%
    }

\newcommand{\simple}[1]{%
    \checkflag{simple}{\simple{Just a plain formatting directive.}}%
    \textsc{#1}%
}

\setlength{\parindent}{0pt}

\begin{document}
\printmacros
\section{Test}
This is some textt\indoubt{Wrong spelling?}~\dots \simple{More text.}
\end{document}
David Carlisle
  • 757,742
  • Thank you very much, this does exactly what I want to achieve here! – Andreas Oct 19 '17 at 12:19
  • OK, after looking for the meaning of \space in "TeX by Topic", which I just discovered yesterday, I understand that this is what I've always been looking for: insert a space anywhere except at the start of a line! Thus, I could have used {\unskip\space{\textbf{[#1]}}} in my definition of \indoubt all along (although \ifhmode … is much more elegant). {\unskip\textbf{\space[#1]}} would not work, however, because it would be local to \textbf{} -- and \textbf{}, not \space would be the first token at the start of a line. Have I got that right? – Andreas Oct 19 '17 at 12:40
  • the \ifhmode is needed to guard the \unskip, as if used at the start of a paragraph, \unskip would remove the vertical space before the paragraph. @Andreas – David Carlisle Aug 14 '21 at 18:37