1

I have written a personal command called \compo that allows you to place a figure next to a text: \compo[.4]{ text }{ figure };

When the figure is created with the tikz calc library, there is this error:

! Package tikz Error: + or - expected.

I installed the tikz babel library and also used \shorthandoff and \shortandon commands, but that doesn't change anything. I guess the problem is my macro. His code is as follows:

%----------------------------------------
% new command \compo to place a figure next to a text
%----------------------------------------
\newlength{\colG}\newlength{\colD}
\newcommand{\compo}[3][0.5]{
\setlength{\colG}{#1\linewidth}
\setlength{\colD}{\linewidth}%
\addtolength{\colD}{-\colG}
\addtolength{\colG}{-10pt}
\addtolength{\colD}{-10pt}%
\par \noindent%
\begin{minipage}[t]{\colG}\vspace{0cm}#2\end{minipage}\hfill\vrule\hfill%
\begin{minipage}[t]{\colD}\vspace{0cm}#3\end{minipage}\par}

Here is a MCE:

\documentclass[a4paper, 11pt]{article} 
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{tikz}               
\usetikzlibrary{calc}        
\usetikzlibrary{babel}     

%----------------------------------------
% new command \compo to place a figure next to a text
%----------------------------------------
\newlength{\colG}\newlength{\colD}
\newcommand{\compo}[3][0.5]{
\setlength{\colG}{#1\linewidth}
\setlength{\colD}{\linewidth}%
\addtolength{\colD}{-\colG}
\addtolength{\colG}{-10pt}
\addtolength{\colD}{-10pt}%
\par \noindent%
\begin{minipage}[t]{\colG}\vspace{0cm}#2\end{minipage}\hfill\vrule\hfill%
\begin{minipage}[t]{\colD}\vspace{0cm}#3\end{minipage}\par}

\begin{document}

\compo[.5]{
  Un triangle 

}{
\shorthandoff{!:}
\begin{tikzpicture}[handle active characters in code]

\draw(-1,-1) rectangle (4,4);
\coordinate (B) at (0,0);
\coordinate  (C) at (3,0);
\coordinate(D) at (2,0);
\draw(B)--(C)--(D)--cycle;
\coordinate (Ap) at ($(C)!.35!-90:(B)$);
\draw (Ap)--(B)--(C)--cycle;
\end{tikzpicture}
\shorthandon{!:}
}

\end{document}

What is the error in the code of this macro \compo? How do I correct this error?

3

The problem is a catcode issue. Here is a more minimal demonstration:

\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}

\newcommand\compo[1]{#1} % compo does nothing but return it's argument
\begin{document}
%%% Works:
\shorthandoff{!}
\compo{
    \begin{tikzpicture}[]
    \coordinate (Ap) at ($(0,0)!0!(3,0)$);
    \end{tikzpicture}
}
\shorthandon{!}

%%% Breaks:
\compo{
    \shorthandoff{!}    % \shorthandoff doesn't do anything because characters in 
    \begin{tikzpicture} % argument have already had their catcodes assigned
    \coordinate (Ap) at ($(0,0)!0!(3,0)$); % so the active ! causes an error here
    \end{tikzpicture}
    \shorthandon{!}
}
\end{document} 

Note that I have replaced your command with one that does nothing but return its argument and it still causes the problem. Why does it cause a problem? Because the catcodes of characters are assigned when they are first parsed. Normally, the ! in the body of the tikzpicture is parsed after the \shorthandoff{!} command changes ! from catcode active to catcode other. However, when the ! occurs in the argument of a command, the entire body of the command is parsed before any of the body is evaluated. Thus, the ! is already active, and the catcode change caused by the \shorthandoff{!} command does nothing. The best fix is to do the catcode change inside the \compo command and call a helpre command to grab the arguments:

\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}

% The wrapper command doesn't take any arguments, it just makes the catcode change and 
% calls the helper.
\newcommand\compo{\shorthandoff{!}\compohelper}
% The helper does all the work.
\newcommand\compohelper[1]{#1\shorthandon{!}}
\begin{document}
\compo{
    \begin{tikzpicture}
    \coordinate (Ap) at ($(0,0)!0!(3,0)$);
    \end{tikzpicture}
}
\end{document} 

Now you can use your original definition for \compohelper and it works as expected:

\documentclass{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{babel}

\newlength{\colG}\newlength{\colD}
% Wrapper command just changes catcodes and calls helper
\newcommand\compo{%
    \shorthandoff{!:}% Change the catcodes
    \compohelper % call helper to grab arguments
}
\newcommand{\compohelper}[3][0.5]{% do actual work
    \setlength{\colG}{#1\linewidth}%
    \setlength{\colD}{\linewidth}%
    \addtolength{\colD}{-\colG}%
    \addtolength{\colG}{-10pt}%
    \addtolength{\colD}{-10pt}%
    \par \noindent%
    \begin{minipage}[t]{\colG}#2\end{minipage}\hfill\vrule\hfill%    
    \begin{minipage}[t]{\colD}#3\end{minipage}%
    \par
    \shorthandon{!:}% restore catcodes
}

\begin{document}
\compo[.5]{
  Un triangle

}{
    \begin{tikzpicture}
        \draw(-1,-1) rectangle (4,4);
        \coordinate (B) at (0,0);
        \coordinate  (C) at (3,0);
        \coordinate(D) at (2,0);
        \draw(B)--(C)--(D)--cycle;
        \coordinate (Ap) at ($(C)!.35!-90:(B)$);
        \draw (Ap)--(B)--(C)--cycle;
    \end{tikzpicture}
}
\end{document} 
  • It's a big step forward, but if I put the figure to the left and the text to the right, the error is repeated. \compo[.4]{ figure }{ text }; – AndréC Oct 21 '17 at 14:36
  • That's an easy fix. I edited it so now it will work both ways. – Hood Chatham Oct 21 '17 at 14:38
  • It's almost perfect, but if I place two identical figures, one on the left and the other on the right, the one on the right is not aligned with the one on the left. The one on the right is at the top, while the one on the left is at the bottom. – AndréC Oct 21 '17 at 14:57
  • Added an edit that should fix that. – Hood Chatham Oct 21 '17 at 16:07
  • It's magical, very nice work, thank you very much! – AndréC Oct 21 '17 at 16:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.