1

I was surprised to copy a character (I'd spent so much time to trim whitespace around) from a \vbox just to discover that it forces a line break whenever it precedes text (on the same line). Below is a simplified version that creates the same outcome. I need @ to appear on the same line as hello world, without enclosing both within an \hbox (this is the only way I discovered that works, but I can't enclose hello world--only @--in my original code due to design issues).

P.S. let's limit solution to plain TeX code compiled in XeLaTeX.

\documentclass[border=5mm,varwidth]{standalone}

\usepackage{color}
\pagecolor{black}
\color{white}

\begin{document}
  \newbox\zT
  \setbox\zT\vbox{\makeatletter@\makeatother}
  \copy\zT hello world\par % try 1 (failed)
  \hbox{\copy\zT}hello world % try 2 (failed)
\end{document}

EXPECTED OUTPUT (APPROXIMATION):

5
  • Why not \makeatletter\newcommand*\letterat{@}\makeatother and then use \letterat instead of a box? Jan 12, 2020 at 7:48
  • 1
    \setbox\zT\hbox{\makeatletter@\makeatother} .... vbox will take the whole linewidth ...
    – koleygr
    Jan 12, 2020 at 7:48
  • It would be much better if you explain what your real problem is.
    – egreg
    Jan 12, 2020 at 9:38
  • \makeatletter@\makeatother ??? is the same as @ Jan 12, 2020 at 10:33
  • 1
    also note that latex does not include plain so you can not have "plain tex code compiled with xelatex" (there is only one command you use there that has the same name as a command defined in plain, \newbox but the version in latex is quite different (especially the version in xelatex) Jan 12, 2020 at 10:35

3 Answers 3

2

P.S. let's limit solution to plain TeX code compiled in XeLaTeX.

there were no commands used in your example that are as defined in plain TeX, plain TeX has a \newbox command but with quite different definition, and none of the other commands are commands defined in plain, they are either LaTeX commands or TeX primitives.

You have not said what you are trying to do, but LaTeX box commands are designed to avoid issues like this (and using tex primitive \setbox after you have loaded color is particularly dangerous, you can easily generate invalid PDF output with no warning)

The LaTeX markup would be

\documentclass[border=5mm,varwidth]{standalone}

\usepackage{color}
\pagecolor{black}
\color{white}

\begin{document}
  \newsavebox\zT
  \sbox\zT{@}

  \usebox{\zT} hello world
\end{document}

enter image description here

To see what is wrong with your original note that a box does not start a paragraph, so in either of

\vbox{...}
Hello World

or

\hbox{...}
Hello World

The paragraph starts at H with the box contents coming before (that is, above) the paragraph.

Normally the solution is to use \leavevmode before the box to start the paragraph so \leavevmode\hbox{@} or better \mbox{@} or with a box register, \leavevmode\copy\zT or better \usebox{\zT}.

But in your case the box would not fit to the left of the H anyway as you have

\vbox{@}

so that is starting a paragraph inside vmode, so the paragraph text (\indent box, @ and \parfillskip) will be wrapped to lines of width \hsize so the vbox contents include an \hbox of width \hsize (which is \textwidth) not just an @.

TeX can show you the box constructed by \vbox{@} :

\documentclass[border=5mm,varwidth]{standalone}

\usepackage{color}
\pagecolor{black}
\color{white}

\begin{document}

\showoutput
\setbox\zT\vbox{@}
\showbox\zT
\end{document}

produces

\vbox(6.94444+0.0)x345.0
.\hbox(6.94444+0.0)x345.0, glue set 337.2222fil
..\hbox(0.0+0.0)x0.0
..\OT1/cmr/m/n/10 @
..\penalty 10000
..\glue(\parfillskip) 0.0 plus 1.0fil
..\glue(\rightskip) 0.0

so the vbox contains an hbox of width \hsize containing a zero sized empty hbox (for paragraph indent), the @ character and \parfillskip and \rightskip glue nodes.

10
  • @bp2017 you will break latex by using unsupported commands. And just because the texbook has a command of the same name doesn't mean that the latex command of that name is the same. As I comment in the answer \newbox is quite different. Jan 12, 2020 at 19:51
  • @bp2017 I honestly can not understand what line of reasoning would say that you can not use \sbox because it is strictly latex but you can use \documentclass and \begin{document} ???? Jan 12, 2020 at 19:53
  • 1
    @bp2017 you should ask a new question, discussing code in comment fomatting is useless. But you need \leavevmode before the copy as I describe in this answer, then the box comes to the left of hello word not above it, it is however all below the baseline as you constructed a vtop starting with a zero kern so that puts the reference point at its top edge. Jan 12, 2020 at 21:32
  • 1
    @bp2017 or perhaps you want it below the baseline? as the same is true of the fbox version. By the way I added \documentclass{article} to the top of your pastebin so it worked at all Jan 12, 2020 at 21:34
  • 1
    @bp2017 I don't suppose you want me to mention that latex arranges that every box command, \mbox, \fbox, \makebox, \usebox, \includegraphics, ... all have definitions that begin with \leavevmode :-) Jan 12, 2020 at 21:51
1

If you want to use plain TeX, don't embed things in LaTeX.

From your post I guess you have a character you want to trim the white space around. For instance, take \times.

This is the character with no white space around it, the hairline box around is just to show the bounding box.

enter image description here

If you want to use the clipped character, you can set it into a box and then \copy the box, but remember that a \copy command does not change from vertical to horizontal mode.

\newbox\btimesbox
% remove the white space on the left and on the right
\setbox\btimesbox=\hbox{\kern-0.35ex$\times$\kern-0.35ex}
% remove the white space at the bottom
\setbox\btimesbox=\hbox{\raise-0.03ex\box\btimesbox}
% we want the depth to be zero
\dp\btimesbox=0pt
% remove the white space at the top
\ht\btimesbox=1.1ex

\def\btimes{\leavevmode\copy\btimesbox}

\btimes\ hello world

t\btimes t

t$\times$t

\bye

enter image description here

1
  • @bp2017 I can't read your mind.
    – egreg
    Jan 12, 2020 at 22:47
1

It doesn't work because a \vbox always automatically has width \hsize which is the width of the whole text block. You could do something like \vbox{\hsize=1em...} but that's just nonsense since there are better solutions.

I have three proposals for you.

  1. Define a macro inside \makeatletter...other. This will freeze the catcode of @ inside the macro, so using the macro to typeset @ will not be affected by surrounding catcodes.

    \makeatletter
    \newcommand*\letterat{@}
    \makeatother
    
  2. Define a character constant. This will insert the character at the code that you provide. Catcodes don't apply to a character constant. The downside is that this costs one register, but with e-TeX nowadays that's not actually an issue.

    \chardef\letterat=`\@
    
  3. Put the character in a hbox. This has a couple of downside. First the character does not adapt to the surrounding font at all, second it also costs a register and third it can't be placed in the preamble because fonts have to be loaded at the time you assign the box.

    \newbox\atbox
    \setbox\atbox=\hbox{@}
    \newcommand*\letterat{\leavevmode\unhcopy\atbox}
    
4
  • There's no reason for using \makeatletter and \makeatother in this context. If we type @, TeX will happily print it.
    – egreg
    Jan 12, 2020 at 9:39
  • @egreg I don't know the exact use-case. OP said it doesn't work to type @ but you're right that the MWE is not reflecting that. Jan 12, 2020 at 9:41
  • 1
    better to say "automatically has the width of its contents" rather than "automatically has width \hsize" \vbox{@} is \hsize wide but \vbox{\hbox{@}} is the width of @ as in the first case it contains a \hbox of width \hsize, but in the second the \hbox is the width of @ Jan 12, 2020 at 15:37
  • +1 for \leavevmode
    – bp2017
    Jan 13, 2020 at 5:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .