9

Based on the method indicated in this post, I want to make a \starredvariant command that would take a command and output the definition of its starred variant.

The point is to be able to use a syntax similar to that of \newcommand, i.e. using brackets as argument delimiters and embedding \WithSuffix.

Edit. Such a command serves a purpose distinct from creating the starred/unstarred pair from scratch (e.g. using the boolean value of an argument of type s, as suggested in several answers). The whole point is to customize a command that is not necessarily yours, or whose coding you do not wish to edit. In sum, the idea is to avoid a low-level redefinition.

Here is what I have come up with:

\NewDocumentCommand{\starredvariant}{
m
O{}
O{}
m}
{\WithSuffix\newcommand#1*[#2][#3]{#4}}

MWE 1

\documentclass{article}
\usepackage{suffix}


\NewDocumentCommand{\starredvariant}{
    m
    O{}
    O{}
    m}
    {\WithSuffix\newcommand#1*[#2][#3]{#4}}

    
\newcommand{\inquotes}[2][]{#1 `#2'}

\starredvariant{\inquotes}[2][]{#1 «\,#2\,»}


\begin{document}
    
    \inquotes[fleur]{flower}
    
    \inquotes*[fleur]{flower}

    \inquotes*{flower}

\end{document}

enter image description here

However, it does not work as expected here below in MWE 2. Any idea why?

MWE 2

\documentclass{article}
\usepackage{changepage}
\usepackage{suffix}
\NewDocumentCommand{\starredvariant}{
    m
    O{}
    O{}
    m}
{\WithSuffix\newcommand#1*[#2][#3]{#4}}



\newcommand{\tsltx}[1]{\normalfont\hspace{\parindent}`#1'}
\starredvariant{\tslt}[1]{\normalfont\hspace{\parindent}`#1'}

\begin{document}


\begin{adjustwidth}{7em}{}
    \tsltx{The Atlantic wears away our coasts. The pressure of the current from the Pole deforms our western cliffs. This wall that shields us from the sea is being undermined from Saint-Valery-sur-Somme to Ingouville; huge blocks of rock tumble down, the sea churns clouds of boulders, our harbors are silted up with sand and shingle, the mouths of our rivers are barred. Every day a stretch of Norman soil is torn away and disappears under the waves. This tremendous activity, which has now slowed down, has had terrible consequences. It has been contained only by that immense spur of land we know as Finistère. The power of the flow of water from the Pole and the violence of the erosion it causes can be judged from the hollow it has carved out between Cherbourg and Brest.
        
    The formation of this gulf in the Channel at the expense of French soil goes back before historical times; but the last decisive act of aggression by the ocean against our coasts can be exactly dated. In 709, sixty years before Charlemagne came to the throne, a storm detached Jersey from France.}
    
\end{adjustwidth}

\vspace{3ex} 

\begin{adjustwidth}{7em}{}
    \tslt*{The Atlantic wears away our coasts. The pressure of the current from the Pole deforms our western cliffs. This wall that shields us from the sea is being undermined from Saint-Valery-sur-Somme to Ingouville; huge blocks of rock tumble down, the sea churns clouds of boulders, our harbors are silted up with sand and shingle, the mouths of our rivers are barred. Every day a stretch of Norman soil is torn away and disappears under the waves. This tremendous activity, which has now slowed down, has had terrible consequences. It has been contained only by that immense spur of land we know as Finistère. The power of the flow of water from the Pole and the violence of the erosion it causes can be judged from the hollow it has carved out between Cherbourg and Brest.
        
    The formation of this gulf in the Channel at the expense of French soil goes back before historical times; but the last decisive act of aggression by the ocean against our coasts can be exactly dated. In 709, sixty years before Charlemagne came to the throne, a storm detached Jersey from France.}
    
\end{adjustwidth}
\end{document}

enter image description here

2

3 Answers 3

9

The error analysis of @Werner is flawless, the issue lies in the fact that you always provide [] to \newcommand. Instead of using O{} the following uses o and checks whether the argument was there.

Please note that I share the views of the two answers by Werner and egreg, you should prefer the s-argument provided by ltcmd over this generator macro, the following just serves to show you the coding error you made.

\documentclass{article}
\usepackage{changepage}
\usepackage{suffix}
\NewDocumentCommand{\starredvariant}{
    m
    o
    o
    m}
{%
  \IfNoValueTF{#3}%
    {%
      \IfNoValueTF{#2}%
        {\WithSuffix\newcommand#1*{#4}}%
        {\WithSuffix\newcommand#1*[#2]{#4}}%
    }%
    {\WithSuffix\newcommand#1*[#2][{#3}]{#4}}% braces around #3 so that it can contain `]`
}



\newcommand{\tsltx}[1]{\normalfont\hspace{\parindent}`#1'}
\starredvariant{\tslt}[1]{\normalfont\hspace{\parindent}`#1'}

\begin{document}


\begin{adjustwidth}{7em}{}
    \tsltx{The Atlantic wears away our coasts. The pressure of the current from the Pole deforms our western cliffs. This wall that shields us from the sea is being undermined from Saint-Valery-sur-Somme to Ingouville; huge blocks of rock tumble down, the sea churns clouds of boulders, our harbors are silted up with sand and shingle, the mouths of our rivers are barred. Every day a stretch of Norman soil is torn away and disappears under the waves. This tremendous activity, which has now slowed down, has had terrible consequences. It has been contained only by that immense spur of land we know as Finistère. The power of the flow of water from the Pole and the violence of the erosion it causes can be judged from the hollow it has carved out between Cherbourg and Brest.
        
    The formation of this gulf in the Channel at the expense of French soil goes back before historical times; but the last decisive act of aggression by the ocean against our coasts can be exactly dated. In 709, sixty years before Charlemagne came to the throne, a storm detached Jersey from France.}
    
\end{adjustwidth}

\vspace{3ex} 

\begin{adjustwidth}{7em}{}
    \tslt*{The Atlantic wears away our coasts. The pressure of the current from the Pole deforms our western cliffs. This wall that shields us from the sea is being undermined from Saint-Valery-sur-Somme to Ingouville; huge blocks of rock tumble down, the sea churns clouds of boulders, our harbors are silted up with sand and shingle, the mouths of our rivers are barred. Every day a stretch of Norman soil is torn away and disappears under the waves. This tremendous activity, which has now slowed down, has had terrible consequences. It has been contained only by that immense spur of land we know as Finistère. The power of the flow of water from the Pole and the violence of the erosion it causes can be judged from the hollow it has carved out between Cherbourg and Brest.
        
    The formation of this gulf in the Channel at the expense of French soil goes back before historical times; but the last decisive act of aggression by the ocean against our coasts can be exactly dated. In 709, sixty years before Charlemagne came to the throne, a storm detached Jersey from France.}
    
\end{adjustwidth}
\end{document}
3
  • Note that \starredvariant can be useful to create a variant of an already existing, possibly imported command. This was the spirit: not having to use a low-level redefinition. Maybe this can be achieved with ltcmd. Commented Jan 24, 2023 at 23:08
  • 1
    @VincentKrebs \NewCommandCopy\fooOrig\foo\RenewDocumentCommand\foo{sm}{\IfBooleanTF{#1}{new foo with #2}{\fooOrig{#2}}}
    – Skillmon
    Commented Jan 25, 2023 at 5:00
  • Could you edit your answer with how to make this a macro? I get confused with the arguments. \NewDocumentCommand{\starredvar}{mm}{\NewCommandCopy\csname#1Orig\endcsname\csname#1\endcsname\RenewDocumentCommand\csname#1\endcsname{sm}{\IfBooleanTF{##1}{... and now I'm confused Commented Jan 29, 2023 at 23:56
9

Don't mix ltcmd (formerly xparse) with suffix.

I don't see how

\newcommand{\inquotes}[2][]{#1 `#2'}
\starredvariant{\inquotes}[2][]{#1 «\,#2\,»}

is better than

\NewDocumentCommand{\inquotes}{sO{}m}{%
  #2 \IfBooleanTF{#1}{\frenchq}{\highq}{#3}%
}
\NewDocumentCommand{\frenchq}{m}{«\,#1\,»}
\NewDocumentCommand{\highq}{m}{`#1'}

or, if you want to avoid the indirection,

\NewDocumentCommand{\inquotes}{sO{}m}{%
  #2 \IfBooleanTF{#1}{«\,#3\,»}{`#3'}%
}

Note that this would add a space in front of the quoted material, whether or not the optional argument is specified. Possibly the last command should instead be defined with

\NewDocumentCommand{\inquotes}{som}{%
  \IfValueT{#2}{#2 }%
  \IfBooleanTF{#1}{«\,#3\,»}{`#3'}%
}
3
  • This is just the solution I stumbled upon, before that I had no idea how to make starred commands. Does s add a star? Commented Jan 24, 2023 at 13:35
  • 1
    @VincentKrebs Yes. You find the doc either in the obsolete texdoc xparse or in texdoc usrguide.
    – egreg
    Commented Jan 24, 2023 at 13:59
  • Ok thank you :) Commented Jan 24, 2023 at 16:13
9

Your \starredvariant silently fails when defining a command that only takes a single argument, and really only works for commands that take an optional argument. To see why, consider this simple example similar to your first MWE; one would expect \abc{123} and \abc*{123} to return ((123)) and [[123]], but it doesn't:

enter image description here

\documentclass{article}

\usepackage{suffix}

\NewDocumentCommand{\starredvariant}{ m O{} O{} m }{%
  \WithSuffix\newcommand#1*[#2][#3]{#4}}

\newcommand{\abc}[1]{((#1))}
\starredvariant{\abc}[1]{[[#1]]}

\begin{document}

\abc{123}

\abc*{123}

\end{document}

Since you necessarily replace the optional arguments with (blank) defaults via O{} in

\NewDocumentCommand{\starredvariant}{ m O{} O{} m }

your \starredvariant\newcommand will necessarily have at least two argument specifications. This, in turn, implies that you will always have an optional argument. For the above to work then, you'll actually have to use

\abc{123}

\abc*[123]

Since you're using LaTeX3 definitions already, it's much easier to just use the provided Boolean conditioning using \IfBooleanTF{.}{<true>}{<false>}:

\NewDocumentCommand{\abc}{ s m }{%
  \IfBooleanTF{#1}
    {((#2))}
    {[[#2]]}}
1
  • Thank you very much! Commented Jan 25, 2023 at 23:34

You must log in to answer this question.

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