In the spirit of my previous questions Defining \xthinspace: Thin space only if not followed by certain characters and Ellipses & Correct Space Factor, I’m trying to define a generic \xspace
-like macro system.
The syntax I’m leaning towards is as follows:
\makexfollow{xfollow}{(always)}{(followed)}{(not followed)}
\addtoxfollowexceptions{x}
\newcommand*{\foo}{foo\xfollow}
\foo \foo x
yielding
foo(always)(not followed)foo(always)(followed)x
By editing & wrapping egreg’s code, I got most of the way there; see my code below. I even figured out how to use \cs:w … \cs_end:
and the :c
specifier to parameterize most of the internal csnames.
The trouble is with the commands \addtoxfollowexceptions
& \removefromxfollowexceptions
; I cannot figure out how to declare them to replace the xfollow
part of the name with something generic.
How can I achieve this?
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\makexfollow}{m m m m}
{
% Token list for “exceptions”
\tl_new:c { g_#1_exceptions_tl }
% Add to list
% Should be `\cs:w addto#1exceptions \cs_end:` or something similar
\NewDocumentCommand{\addtoxfollowexceptions}{m}
{
\tl_gput_right:cn { g_#1_exceptions_tl } { ##1 }
}
% Remove from list
% Should be `\cs:w removefrom#1exceptions \cs_end:` or something similar
\NewDocumentCommand{\removefromxfollowexceptions}{m}
{
\tl_gremove_all:cn { g_#1_exceptions_tl } { ##1 }
}
\cs_new_protected:cpn { #1 }
{
% Unconditional part
#2
% Is next token one of the “exceptions”?
\bool_set_false:c { l_#1_followed_bool }
% Peek ahead, ignoring spaces, then hand-off to `\xfollow_check:`
% with `\l_peek_token` set.
%
% This is a clever hack: We’re actually checking whether the next
% non-space token is a space token; if not, call `\xfollow_check:`.
% Of course, by definition this will always test false, achieving
% the result described above.
\peek_catcode_ignore_spaces:NF \c_space_token
{ \cs:w #1_check: \cs_end: }
}
% Compare `\l_peek_token` against `\g_xfollow_exceptions_tl`
\cs_new_protected:cpn { #1_check: }
{
% Loop over exceptions list
\tl_map_inline:cn { g_#1_exceptions_tl }
{
\token_if_eq_charcode:NNT ####1 \l_peek_token
{
% Tokens match; set flag and break from loop
\bool_set_true:c { l_#1_followed_bool }
\prg_map_break:
}
}
% Conditional part
\bool_if:cTF { l_#1_followed_bool }
{#3}
{#4}
}
}
\ExplSyntaxOff
\makexfollow{xfollow}{(always)}{(followed)}{(not followed)}
\addtoxfollowexceptions{x}
\newcommand*{\foo}{foo\xfollow}
\begin{document}
\foo \foo x
\end{document}