[Tex/LaTex] How come the tilde ~ sometimes does not behave like non-breaking space


This is again one of the behaviors that are quite difficult to catch in a reconstructible (and simple) example, so one has to resort to animations.

Basically, the issue is this: the tilde (~) is supposed to be a non-breaking space character, right? How come, then, when I use the Fig.~\ref{fig:myfigure} in the MWE below, it sometimes ends up breaking the line exactly at that ~ character's location, as can be seen on the .gif below:


For instance, frame 41 there ends up like this (click for full res):


Isn't that what the tilde is supposed to prevent?

How can I find out why this is happening – and how can I get a non-breaking space in my Fig.~\ref{...} construct?

Below is the MWE, test-tilde.tex; it uses the package repeat-build.sty that I posted here (tested only on Linux currently) – and it needs to be built twice, with -shell-escape:

pdflatex -shell-escape test-tilde.tex # first time, refs wrong here
pdflatex -shell-escape test-tilde.tex # second time, refs ok (can enable the `convert` post action if desired)

… so that all PDFs, used in the animaton above, are generated.

EDIT: I modified the code, so it will build without the repeat-build.sty; and it will reconstruct the situation on the still screenshot above (where the variable \tester=87); then if you want to use repeat-build, simply (un)comment the corresponding lines.

The code is:


\usepackage[demo]{graphicx} %
\usepackage{xcolor} % \pagecolor

% https://tex.stackexchange.com/a/26808/2595
    \edef#3{#3\csname lipsum@\romannumeral\count@\endcsname}%
% https://tex.stackexchange.com/a/168754/2595
  \StrMid{\myunpacked}{1}{#2}% same as \StrLeft{\myunpacked}{#2}
  % \StrMid is not an expandable macro (can't go in \def) - but
  % can "return" by saving in #3
  \typeout{Lorem paragraph #1 has #2 characters}.

\usepackage[format=plain,font=small,skip=12pt]{caption} %
\usepackage{listings} %
\usepackage{units} %
\usepackage{txfonts} % Times font in math; tlmgr install txfonts
\usepackage[UTF8]{ctex} % needs simsun.ttc in same directory
\let\l@AMERICAN\l@american % https://tex.stackexchange.com/q/88861/

% here, set the \tester at a number,
% so we don't hit an error if we
% compile without repeat-build (-shell-escape)

% https://tex.stackexchange.com/a/185976/2595
%%%% uncomment the below part if you want to use {repeat-build}:
%   \ifx\tester\undefined{%
%     \global\protected\def\tester{100} %
%   }\fi
%   % do not rm the .aux here; need them for fig label;
%   % since the process needs to run twice for correct
%   % label - comment the convert post action.
%   %% manual convert command:
%   %% convert -verbose -density 150 test-tilde-*.pdf[0] -crop 1024x580+137+773 -resize 512x +repage -delay 15 -loop 0 test-tilde.gif
%   %% gifsicle -O2 test-tilde.gif -o test-tilde-O2.gif # helps reduce size
%   \def\pacode{%
%     pwd; %
%     ls \jobname-*.log \jobname-*.aux; %
%     rm -vrf \jobname-*.log ;% \jobname-*.aux; %
%   %   convert -verbose -density 75 \jobname-*.pdf[0] %
%   %     -crop 512x290+68+386 %
%   %     +repage %
%   %     -delay 15 -loop 0 % -delay 5
%   %     \jobname.gif %
%   %   ; %
%   %   eog \jobname.gif ; % run viewer
%   }
%   \usepackage[%
%     vartoken=\tester,%  % loop the variable token: \tester
%     varvals={15,16,...,29,41,42,...,52,58,59,...,65,77,78,...,89},% set \tester to change; (was from 0 to 100 {0,...,100})
%     postactioncode={\pacode},%
%   ]{repeat-build}
%   \unprotect\tester
%   \makeatletter
%   \def\getrjname{\rpbuild@jobname}
%   \makeatother
%%%% else this should be enough for a usual run:
\def\tester{83} % comment this if using repeat-build!


  \title{Test title}


  The abstract text goes here.

  \section{Test section}

  Test text, before figure:

  \setcounter{figure}{22} % if 10, then {figure} becomes 11
    %\caption[shortdesc]{The figure is being shown here. \protect\loremnchars[3]{255}}
    \captionof{figure}[shortdesc]{The figure is being shown here. \protect\loremnchars[3]{255}}

  Current: doc: \jobname; \verb!\tester!: \tester ... \loremnchars[1]{150}

  \eloremnchars{2}{\tester}{\tretA} %
  \pgfmathtruncatemacro{\tB}{\tester/2} %
  \eloremnchars{4}{\tB}{\tretB} %
  \eloremnchars{5}{\tester}{\tretC} %
  \tretA\space on Fig.~\ref{fig:myfigure}.
  \tretB\space on Fig.~\ref{fig:myfigure},
  \tretC\space on Fig.~\ref{fig:myfigure}.

  \loremnchars[3]{712}.. And ... \lipsum[7]

  %\getLoremParaNumChars{3}{\tret} %\typeout{\tret}
  %\eloremnchars{3}{712}{\tret} \typeout{\tret}


Best Answer

Here's the MWE that was missing from the question:

  Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi.
  Morbi auctor \space on Fig.~23. Quisque ullamcorper placerat ipsum. 
  Cras \space on Fig.~23, Fusce mauris. Vestibulum luctus nibh at lectus. Sed 
  bibendum, nulla a faucibus semp \space on Fig.~23.

Uncommenting the \show~ tells us

> ~=macro:
->\hspace {0.25em plus 0.125em minus 0.08em}\ignorespaces . 
l.4   \show~

ie, breakable space, and removing the \usepackage{ctex} line sets it back to the usual

> ~=macro:
->\nobreakspace {}.
l.4   \show~

If you must use ctex then it seems that you can replace ~ by \nbs or you can use \standardtilde to restore the usual behaviour of ~.