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

debuggingline-breakingtilde

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:

test-tilde-O2.gif

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

test-tilde-41.png

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:

\documentclass[%
  12pt,
  journal,
  onecolumn,
  twoside,
  draftcls,
  letterpaper,
]{IEEEtran}

\usepackage[demo]{graphicx} %
\usepackage{xcolor} % \pagecolor
\pagecolor{yellow!15}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}

\usepackage[nopar]{lipsum}
\usepackage{xstring}
% https://tex.stackexchange.com/a/26808/2595
\makeatletter
\def\unpacklipsum#1#2#3{%
  \count@=#1\relax
  \advance\count@\m@ne
  \def#3{}%
  \loop\ifnum\count@<#2\relax
    \advance\count@\@ne
    \edef#3{#3\csname lipsum@\romannumeral\count@\endcsname}%
  \repeat}
% https://tex.stackexchange.com/a/168754/2595
\def\loremnchars[#1]#2{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  \StrMid{\myunpacked}{1}{#2}% same as \StrLeft{\myunpacked}{#2}
}
\def\eloremnchars#1#2#3{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  % \StrMid is not an expandable macro (can't go in \def) - but
  % can "return" by saving in #3
  \StrMid{\myunpacked}{1}{#2}[#3]
}
\def\getLoremParaNumChars#1#2{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  \StrLen{\myunpacked}[#2]
  \typeout{Lorem paragraph #1 has #2 characters}.
}
\makeatother

\usepackage[format=plain,font=small,skip=12pt]{caption} %
\usepackage{listings} %
\usepackage{units} %
\usepackage{floatrow}
\floatsetup[figure]{capposition=bottom}
\usepackage{etoolbox}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{tikz}
\usetikzlibrary{shapes,positioning}
\usetikzlibrary{fit}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}
\usepackage{txfonts} % Times font in math; tlmgr install txfonts
\renewcommand{\ttdefault}{pcr}
\usepackage[UTF8]{ctex} % needs simsun.ttc in same directory
\usepackage{setspace}
\usepackage{siunitx}
\usepackage[american]{babel}
\usepackage{csquotes}
\makeatletter
\let\l@AMERICAN\l@american % https://tex.stackexchange.com/q/88861/
\makeatother
\usepackage[style=ieee,isbn=true,doi=false,url=true,backend=biber]{biblatex}


% 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!

\begin{document}

  \title{Test title}
  \author{test}

  \maketitle

  \begin{abstract}
  The abstract text goes here.
  \end{abstract}

  \section{Test section}

  Test text, before figure:

  \setcounter{figure}{22} % if 10, then {figure} becomes 11
  \begin{figure}[h!t]
    \singlespacing
    \includegraphics[width=\textwidth,height=100pt]{demo.whatever}
    %\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}}
    \label{fig:myfigure}
  \end{figure}

  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}

\end{document}

Best Answer

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

\documentclass[12pt,onecolumn,draftcls]{IEEEtran}
\usepackage{ctex}
\begin{document}
%\show~
  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.
\end{document}

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 ~.