Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hideerrors does not replace undefined color with black in tikzpicture #15

Open
akloeckner opened this issue Mar 30, 2022 · 5 comments
Open

Comments

@akloeckner
Copy link

When I try to compile the following MWE with an up to date MikTeX setup, I get errors from TikZ/PGF.

\documentclass{article}
\usepackage[hideerrors]{xcolor}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
	\draw[fill=blackkkk]      (0.0,0) rectangle ++(.4,.4);
\end{tikzpicture}
\end{document}

I would expect to have a black square in the output, because the hideerrors option should replace the undefined color blackkkk with black and issue a warning.

Here's the relevant part of the log:

Package xcolor Warning: Undefined color `blackkkk' on input line 7.

! Missing \endcsname inserted.
<to be read again> 
                   \let 
l.7 ...blackkkk]      (0.0,0) rectangle ++(.4,.4);
                                                  
The control sequence marked <to be read again> should
not appear between \csname and \endcsname.

)
! Incomplete \ifx; all text was ignored after line 7.
<inserted text> 
                \fi 
<*> ./xcolor.tex
                
The file ended while I was skipping conditional text.
This kind of error happens when you say `\if...' and forget
the matching `\fi'. I've inserted a `\fi'; this might work.

! Emergency stop.
<*> ./xcolor.tex
                
*** (job aborted, no legal \end found)

Some background on my usecase: I try to write colors to the aux file after they are used. That way, they will be undefined in the first run but will be defined in subsequent runs. For this, I need this first run to succeed and not be aborted. That's what hideerrors is supposed to do, I think. I am sure, it did work some time ago, but I cannot name the date or version, when that was the case...

Am I right to file the issue here? What can be done to fix this?

@u-fischer
Copy link
Member

hideerrors doesn't catch \colorlet, so after \colorlet{mycolor}{blub} is undefined and not black. You could try the following, but I'm not sure if it catches everything.

\documentclass{article}
\usepackage[hideerrors]{xcolor}

%
\makeatletter
\ifcolorerrors@
\else
\def\XC@col@rlet[#1]#2[#3]#4%
 {\begingroup
  \edef\@@cls{#1}\XC@edef\@@nam{#2}\XC@sdef\@@mod{#3}\XC@edef\@@clr{#4}%
  \XC@info\@@clr\@@tmp\XC@@tstfalse
  \ifnum\@@tmp=\@ne\ifx\@@mod\@empty
    \ifx\@@cls\@empty
      \XC@@tsttrue
    \else
      \ifcsname \@backslashchar color@\@@clr\endcsname
       \edef\@@tmp
        {\expandafter\expandafter\expandafter\@secondoffive
          \csname\@backslashchar color@\@@clr\endcsname}%
      \else
       \edef\@@tmp
        {\expandafter\expandafter\expandafter\@secondoffive
          \csname\@backslashchar color@black\endcsname}%
      \fi
      \ifx\@@cls\@@tmp\XC@@tsttrue\fi
    \fi
  \fi\fi
  \ifXC@@tst
    \XC@logdef\@@nam\XC@c@l@rlet\@@nam\@@clr
  \else
    \extractcolorspec\@@clr\@@clr
    \ifx\@@mod\@empty\else
      \expandafter\convertcolorspec\@@clr\@@mod\@@clr
      \edef\@@clr{{\@@mod}{\@@clr}}\fi
    \edef\@@tmp{\noexpand\XC@definecolor[\@@cls]{\@@nam}\@@clr}%
  \fi
  \expandafter\endgroup\@@tmp\xglobal@stop}
  
\def\XC@c@l@rlet#1#2%
 {\@ifundefinedcolor{#2}%
   {\c@lor@error{`#2'}\let\@@tmp\@empty
    \edef\@@tmp{%
     \noexpand\XC@let@cc{\@backslashchar color@#1}{\@backslashchar color@black}}   
   }%
   {\edef\@@tmp
     {\ifglobalcolors\global\else\xglobal@\fi
      \noexpand\XC@let@cc{\@backslashchar color@#1}{\@backslashchar color@#2}}}}  
\makeatother
\fi 


\usepackage{tikz}
\begin{document}

\colorlet{blub}{black!50!red}
\color{blub} aaaaa 

\begin{tikzpicture}
	\draw[fill=redx]      (0.0,0) rectangle ++(.4,.4);
\end{tikzpicture}

\end{document}

@akloeckner
Copy link
Author

Thanks for your feedback! Unfortunately, I do not understand what that code does. So, I cannot judge, if it catches everything. It does work for my usecase, however.

Your comments also pointed me in a another workaround direction:

  • \colorlet is not affected by hideerrors
  • colors can be mixed

So, I found out, that this also works (notice the color redx!100):

\documentclass{article}
\usepackage[hideerrors]{xcolor}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
	\draw[fill=redx!100]      (0.0,0) rectangle ++(.4,.4);
\end{tikzpicture}
\end{document}

Might it be a solution to just append !100 any time \colorlet is used?

@u-fischer
Copy link
Member

Might it be a solution to just append !100 any time \colorlet is used?

not sure who you think can append that. But if xcolor handles \colorlet{new}{unknown!100} but not \colorlet{new}{unknown} when hideerrors is activated then we should imho correct that. But be aware that this handles only xcolor, tikz (and other packages) also use sometimes internal color commands which bypass xcolor and that can still fail. Imho it would be better to ensure that all colors are correctly defined before you use them.

@akloeckner
Copy link
Author

xcolor handles \colorlet{new}{unknown!100} but not \colorlet{new}{unknown} when hideerrors is activated

That is the case. I reduced the example to a pure xcolor one relying only on \colorlet.
(I hope, I got the internal macros right.)

In this example, redx=redy is empty, while redz=redy!100 is the same as black.

\documentclass{article}
\usepackage[hideerrors]{xcolor}
\usepackage[T1]{fontenc}

\begin{document}
\makeatletter

black: \expandafter\meaning\csname\@backslashchar color@black\endcsname

redx: \expandafter\meaning\csname\@backslashchar color@redx\endcsname
	
\colorlet{redx}{redy}

redx=redy: \expandafter\meaning\csname\@backslashchar color@redx\endcsname

\colorlet{redz}{redy!100}

redz=redy!100: \expandafter\meaning\csname\@backslashchar color@redz\endcsname

\end{document}

This results in:

black: macro:->\xcolor@ {}{0 g 0 G}{gray}{0}
redx: \relax
redx=redy: \relax
redz=redy!100: macro:->\xcolor@ {}{0 g 0 G}{gray}{0}

@muzimuzhi
Copy link

After some checking, I think all cases are caught by the patch provided in #15 (comment).

Since both showerrors and hideerrors class options replace undefined color by "black" after displaying a message, the the only difference between them is the type of message (error vs warning), and the logic \ifcolorerrors@ ... \else ... \fi is only needed to be used in \c@lor@error.

Here's a slightly shorter patch, by changing

\@ifundefinedcolor{<color>}
  {\c@lor@error{`<color>'}
   \edef\@@tmp{... \@backslashchar color@black ...}}
  {\edef\@@tmp{... \@backslashchar color@<color> ...}}

to

\@ifundefinedcolor{<color>}
  {\c@lor@error{`<color>'}\def\@@tmp{black}}
  {\def\@@tmp{<color>}}
\edef\@@tmp{... \@backslashchar color@\@@tmp ...}
\documentclass{article}
\usepackage[hideerrors]{xcolor}

\makeatletter
\def\XC@col@rlet[#1]#2[#3]#4%
 {\begingroup
  \edef\@@cls{#1}\XC@edef\@@nam{#2}\XC@sdef\@@mod{#3}\XC@edef\@@clr{#4}%
  \XC@info\@@clr\@@tmp\XC@@tstfalse
  \ifnum\@@tmp=\@ne\ifx\@@mod\@empty
    \ifx\@@cls\@empty
      \XC@@tsttrue
    \else
      \@ifundefinedcolor\@@clr
        {\def\@@tmp{black}}% just in case "black" is redefined to be "named"
        {\def\@@tmp{\@@clr}}%
      \edef\@@tmp
        {\expandafter\expandafter\expandafter\@secondoffive
          \csname\@backslashchar color@\@@tmp\endcsname}%
      \ifx\@@cls\@@tmp\XC@@tsttrue\fi
    \fi
  \fi\fi
  \ifXC@@tst
    \XC@logdef\@@nam\XC@c@l@rlet\@@nam\@@clr
  \else
    \extractcolorspec\@@clr\@@clr
    \ifx\@@mod\@empty\else
      \expandafter\convertcolorspec\@@clr\@@mod\@@clr
      \edef\@@clr{{\@@mod}{\@@clr}}\fi
    \edef\@@tmp{\noexpand\XC@definecolor[\@@cls]{\@@nam}\@@clr}%
  \fi
  \expandafter\endgroup\@@tmp\xglobal@stop
}

\def\XC@c@l@rlet#1#2%
  {\@ifundefinedcolor{#2}%
    {\c@lor@error{`#2'}\def\@@tmp{black}}
    {\def\@@tmp{#2}}
   \edef\@@tmp
     {\ifglobalcolors\global\else\xglobal@\fi
       \noexpand\XC@let@cc{\@backslashchar color@#1}{\@backslashchar color@\@@tmp}}}
\makeatother

\begin{document}
\ExplSyntaxOn
\cs_new_protected:Npn \colorlogmeaning #1
  {
    \tl_log:e { color~"#1":~ \cs_meaning:c { \c_backslash_str color@#1 } }
  }
\ExplSyntaxOff

% \definecolor{black}{cmyk}{1,1,1,1} % test with a modified "black"
\colormeaning{black}       % color "black"

\colormeaning{redx}        % color undefined

\colorlet{redx}{redy}      % xcolor warning or error "Undefined color 'redy'"
\colormeaning{redx}        % color "black"

\colorlet{redx}[rgb]{redy} % xcolor warning or error "Undefined color 'redy'"
\colormeaning{redx}        % color "black"
\end{document}

In log

> color "black": macro:->\xcolor@ {}{0 g 0 G}{gray}{0}.
> color "redx": undefined.


Package xcolor Warning: Undefined color `redy' on input line 59.

> color "redx": macro:->\xcolor@ {}{0 g 0 G}{gray}{0}.

Package xcolor Warning: Undefined color `redy' on input line 62.

> color "redx": macro:->\xcolor@ {}{0 0 0 rg 0 0 0 RG}{rgb}{0,0,0}.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants