TransWikia.com

Using newcommand in an environment

TeX - LaTeX Asked by Alois Pichler on June 1, 2021

A command can be employed as an environment.

The macro

newcommand{rev}[2][blue]{{color{#1}#2}}

simply colors its argument, for example.

Why does the corresponding environment not color the entire content?

begin{document}
    black  % is correct
    rev{in blue} rev[red]{in red}  % correct
    black  % correct

    begin{rev}in blueend{rev}% only first letter is blue
    begin{rev}[red]           % only first letter is red
        in red
    end{rev}
    black again  % black again
end{document}

As well, rev[normalcolor]{text} should work fine.

2 Answers

It is possible to check whether the macro is used as an environment or as a normal command by checking against @currenvir. The following uses this to either call color (which will colour the entire contents of the environment), or textcolor (which will only colour the mandatory argument).

documentclass[]{article}

usepackage[]{color}
makeatletter
newcommandrev[1][blue]
  {%
    begingroup
      deftmp{rev}%
      expandafter
    endgroup
    ifxtmp@currenvir
      expandaftercolor
    else
      expandaftertextcolor
    fi
    {#1}%
  }
makeatother

begin{document}
    black  % is correct
    rev{in blue} rev[red]{in red}  % correct
    black  % correct

    begin{rev}in blueend{rev} % only first letter is blue
    begin{rev}[red]            % only first letter is red
        in red%
    end{rev}
    black again  % black again
end{document}

Note that this isn't fool-proof. A usage such as begin{rev}abcrev[red]{def}ghiend{rev} will result in abc being blue, and defghi being red.


A perhaps better way to check whether rev is used as an environment is to use LaTeX's hook mechanism to set a boolean that indicates that the current rev is an environment (and let the environment version set the boolean back to false). This would also work for cases such as begin{rev}abcrev[red]{def}ghiend{rev}.

documentclass[]{article}

usepackage[]{color}
makeatletter
newififrev@inenv
ifdefinedAddToHook
  AddToHook{env/rev/begin}{rev@inenvtrue}
else
  usepackage{etoolbox}
  AtBeginEnvironment{rev}{rev@inenvtrue}
fi
newcommandrev[1][blue]
  {%
    ifrev@inenv
      rev@inenvfalse
      expandaftercolor
    else
      expandaftertextcolor
    fi
    {#1}%
  }
makeatother

begin{document}
    black  % is correct
    rev{in blue} rev[red]{in red}  % correct
    black  % correct

    begin{rev}in blueend{rev} % only first letter is blue
    begin{rev}[red]            % only first letter is red
      in redrev[green]{test}ed%
    end{rev}
    black again  % black again
end{document}

(I made an edit which checks whether AddToHook is available, and if not falls back to etoolbox)

Correct answer by Skillmon on June 1, 2021

begin{rev}[red]           % only first letter is red
        in red
    end{rev}

is more or less

begingrouprev[red]
   in red
   relaxendgroup

which is equivalent to

begingrouprev[red]{i}%
   n red
   relaxendgroup

By the built in rules of parsing for tex macro arguments.


If you want to define an environment where the body of the environment acts as a macro parameter, use NewDocumentEnvironment and a b argument. This requires the xparse package in older latex fromats but is built in to current releases.

Of course for the specific example of color no argument is needed, just use color{red} and the scope of the colour change will end at the end of the environment.

Answered by David Carlisle on June 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP