Not an answer, more a comment with a picture:
The locally defined \ul
is no longer \relax
ed when copy-pasting @egreg's expl3 code from Defining commands that are scoped to a particular environment exactly, which gives this result (outside the environment = red; inside the environment = blue):
MWE
\documentclass[a4paper,12pt]{report}
\newcommand\textdescenders{pqrgym}
\usepackage{ulem}
\usepackage{contour}
\newcommand{\ul}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{red}{#1}}
}
%%\usepackage{xparse}
%%
%%\ExplSyntaxOn
%%\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
%%{
%% \tl_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
%% \tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
%% \exp_args:Nc \newcommand { w envc_#1_\cs_to_str:N #2 }
%%}
%%\NewDocumentCommand{\checkenvcommands}{ }
%%{
%% \tl_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
%% {
%% \tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
%% {
%% \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 }
%% }
%% }
%%}
%%\ExplSyntaxOff
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
{
\cs_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
\tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
\exp_after:wN \newcommand \cs:w envc_#1_\cs_to_str:N #2 \cs_end:
}
\NewDocumentCommand{\checkenvcommands}{ }
{
\cs_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
{
\tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
{ \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 } }
}
}
\ExplSyntaxOff
%--Taking the bit below out restores normal underlining
\newenvcommand{shaded}{\ul}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{blue}{#1}
% \uline{#1}\\
% \contour{blue}{#1}
}
}
\newenvironment{shaded}{\checkenvcommands}{}
%\input{the-above-code.tex}
\contourlength{0.6pt}
\begin{document}
\Huge
{\normalsize \textbackslash uline as is: }
\uline{Test outside shaded. \textdescenders}
\vspace{2ex}
{\normalsize \textbackslash ul with \texttt{contour:}}
\ul{Test outside shaded. \textdescenders}
{\normalsize environment \texttt{shaded} with local \textbackslash ul:}
\begin{shaded}
%\show\ul
\ul{Test inside shaded. \textdescenders } %--Displays white edge if I take out the \newenvcommand{shaded}{\ul}[1]{…} bit, fails when I put it back.
\end{shaded}
\end{document}
I still don't see why contour
would be needed, or how it could have an effect, since the contour halo is not even reaching far enough to affect the line. But that is unrelated.
egreg's code is always interesting.
Edited to add:
Ah, I think I've worked out why the background circumstances of the question sound so bizarre to me: it's because the ulem
package by default does this (which is perfectly OK):
And there are two parameters controlling the line -- thickness, via \ULthickness
:
and depth, via \ULdepth
:
The documentation says that default value for \ULdepth
is \maxdimen
, which changes with the font. So if something is (re)setting \maxdimen
to a small or zero value (or no value), and/or setting \ULdepth
is not an available action to push the underline back down again (for example, the command is being \relax
ed by something more important (and, as yet, unspecified)), then the underline will go through the descenders, as described in the comments. Then, in turn, if a non-ulem
workaround is being sought, we arrive at how contour
might enter into the picture (indeed, there are old questions/answers on point).
Simple (if that is what's happened).
I thought that perhaps I might have had a different version of ulem
, but, since the last update was 2011, that seems unlikely.
As a logistics choice, my inclination would be to start with ulem
first, rather than begin with co-opting (an)other package(s), simply because of the implied dependencies being embedded into the maintenance of the solution by that second method. However, that is a different question, and unrelated.
Edit 2:
Contour
and ulem
work perfectly fine with the different colours:
If you want to use egreg's code for scoping commands inside environments, there are three things to do: (1) check for any typing errors that may have crept in when copying from 'over', wherever 'over' is - e.g. how many d
s are there in the names?; (2) use egreg's code, as per the linked question is a good source; and (3) actually use the code - defining something is just the first step.
The way you have coded shows that the \ul
you are using in the shaded
environment is:
not the one you are intending.
Hint: identify the environment that is actually using the \checkenvcommands
command.
The easiest way is to copy egreg's code from the linked question, define your environment that uses that code, and then the \ul
is scoped to that environment. Once you do all those changes, the result is:
MWE:
\documentclass[a4paper,12pt]{report}
\newcommand\testdescenders{pqgrym}
\usepackage{ulem}
\usepackage{contour}
\renewcommand{\ULdepth}{1.8pt}
\contourlength{0.8pt}
\newcommand{\ul}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{white}{#1}}
}
%-- Shaded environment:
\usepackage{framed,xcolor}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
{
\cs_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
\tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
\exp_after:wN \newcommand \cs:w envc_#1_\cs_to_str:N #2 \cs_end:
}
\NewDocumentCommand{\checkenvcommands}{ }
{
\cs_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
{
\tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
{ \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 } }
}
}
\ExplSyntaxOff
\definecolor{shadecolor}{rgb}{.6,.8,.9}
\newenvcommand{xshaded}{\ul}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{shadecolor}{#1}}
}
\newenvironment{xshaded}{\checkenvcommands\begin{shaded}}{\end{shaded}}
\begin{document}
\ul{Test outside shaded \testdescenders .}
\begin{xshaded}
\ul{Test inside shaded \testdescenders .}
\end{xshaded}
\end{document}
If you want to redefine framed
package's shaded
environment, that should be a separate question.
=====
Edit
For reference, etoolbox
package provides a way to patch existing environments, so the code simplifies to:
MWE
\documentclass[a4paper,12pt]{report}
\newcommand\testdescenders{pqgrym}
\usepackage{ulem}
\usepackage{contour}%default: copies mode; default # copies = 16
%bring the underline nearer to the baseline
\renewcommand{\ULdepth}{1.8pt}
%set a small width of the halo around the text
\contourlength{0.8pt}
%underline is drawn first, then the overlapping text
%white: assumes page colour is white
\newcommand{\ul}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{white}{#1}}
}
% framed provides shaded environment:
\usepackage{framed}
\usepackage{xcolor}
\definecolor{shadecolor}{rgb}{.85,.9,.95}
%define command to define local-scope command and repoint environment to local token-list
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newenvcommand}{ m m } % #1 = env name, #2 = command name
{
\cs_if_exist:cF { g_envc_#1_list_tl } { \tl_new:c { g_envc_#1_list_tl } }
\tl_gput_right:cn { g_envc_#1_list_tl } { #2 }
\exp_after:wN \newcommand \cs:w envc_#1_\cs_to_str:N #2 \cs_end:
}
\NewDocumentCommand{\checkenvcommands}{ }
{
\cs_if_exist:cT { g_envc_\use:c {@currenvir} _list_tl }
{
\tl_map_inline:cn { g_envc_\use:c {@currenvir} _list_tl }
{ \cs_set_eq:Nc ##1 { envc_\use:c {@currenvir} _\cs_to_str:N ##1 } }
}
}
\ExplSyntaxOff
%define a local command \ul for framed's shaded environment
\newenvcommand{shaded}{\ul}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{shadecolor}{#1}}
}
%patch framed's shaded environment to check for local commands
\usepackage{etoolbox}
\AtBeginEnvironment{shaded}{\checkenvcommands}
\begin{document}
\ul{Test outside shaded \testdescenders .}
\begin{shaded}
\ul{Test inside shaded \testdescenders .}
\end{shaded}
\end{document}
Unrelated: If time is a consideration, then compilable code illustrating the problem (an MWE) will more likely generate an answer sooner, in the 6 min - 6 hr range (P > 0.90), rather than the 6 day - 6 week range (P < 0.10) - or never - that a buggy set of random code snippets ever would.
However, since I had earlier (slowly) worked out how to patch contour
to run in outline mode under xelatex (in effect, passing pdf literals to the output via xdvipdfmx's \special
command), interest in how contour
was being applied here has led to a great deal of learning and knowledge, precisely because of "a buggy set of random code snippets".
Contour
puts a halo around the letters, following the contours of the glyphs, exactly for the purpose of making the text more legible when placed over an image, graph or shaded background. There is an illustration in the documentation. Default is 16 contours. Why not just do\uline{some text}
? Unrelated: your code snippet is missing a}
.contour
places copies of the text underneath (with\rlap
) when theoutline
package option is not being used, using sin and cos to position them with a small circular motion offset, to get the halo effect. For multiple colours, you could perhaps insert code into its loop, making the colour a variable, dependent on (a modulo of) the iteration.\begin{document} \ul{Test outside shaded.} \begin{shaded} \ul{Test inside shaded.} \end{shaded} \end{document}
. I didn't think I'd have to do that to give you context.}
was a mis-paste when I copied it over to StackExchange. Thanks for pointing that out.shaded
, but not also an environmentshaded
: add\newenvironment{shaded}{\checkenvcommands}{}
to your code. : see tex.stackexchange.com/questions/48073/… (2) Doing a\show\ul
inside shaded environment puts>\ul\=relax
into the log, so the\ul
expands to nothing and the rest prints as normal. (3) Unrelated: when I use\uline{}
, it goes underneath the descenders, and nothing is cut off anywhere.