How can I calculate a number of lines needed to fit the text?

There are two ways that you can do this: one is with \prevgraf, and the other by calculating the lines manually.

If you do it with \prevgraf, that gives you the amount of lines in the previous paragraph. This will only work if your input is meant to be only one paragraph. What we do is we use \setbox0 to put the text into a vbox which we don't print. In the vbox, we set the hsize to your width, the second argument, and then print the first argument as a paragraph. We manually end the paragraph with \par, and the use \xdef to save the current value of \prevgraf into the cs you passed as the third argument.

\def\CalcNumber#1#2#3{%
  \setbox0\vbox{\hsize=#2 \noindent#1\par\xdef#3{\the\prevgraf}}}

If your input is more than one paragraph, then you can use the same setup as follows:

\makeatletter
\long\def\CalcNumber#1#2#3{%
  \setbox0\vbox{\hsize=#2 \noindent#1}}
\@tempcnta=\dimexpr(\ht0+\dp0)/\baselineskip
\xdef#3{\the\@tempcnta}}
\makeatother

In a similar fashion to our other approach, we typeset our text in a box. We need to define our \CalcNumber as \long, so it can accept text of more than one paragraph. Then, we add the height and depth of the box, and divide by \baselineskip, saving it in a LaTeX temporary count register (this will round the number for us). We then store this in our give control sequence, as above.

A caveat here is that this will use whatever the baselineskip is when you call the macro. You'd need to account for variations in font sizes, depending on what you plan on using this for.


FWIW, ConTeXt provides a macro \determinenofline{...} that determines the number of lines of the content (when typeset in a \vbox). The result is stored in the counter: \noflines.

This counts the number of typeset lines (not the height in the multiple of \lineheight (or what is called \baselineskip in LaTeX). Here is one example from supp-box.mkiv to show that:

\starttext

\determinenoflines{test\\test}
\the\noflines

\determinenoflines{\bfd test\\test}
\the\noflines

\determinenoflines{\definedfont[Sans at 40pt]test\\test}
\the\noflines
\stoptext

All three of these tests give 2.

To count the number of lines for a content of a specific width, you can simply set \hsize for the content. For example:

\starttext
\vbox{\hsize=3cm \input ward\relax}

\determinenoflines{\hsize=3cm \input ward\relax}
\the\noflines
\stoptext

which gives (the first \vbox is just to verify the result).

enter image description here


This is an attempt based on the lineno package.

\documentclass{article}
\usepackage[running]{lineno}
\usepackage{lipsum}
\newcounter{mylines}
\newsavebox{\marmot}
\newcommand{\CalcNumber}[3]{
\savebox{\marmot}{\begin{minipage}{#2}\linenumbers*
\begin{internallinenumbers}
#1 \par
\setcounter{mylines}{\thelinenumber}\addtocounter{mylines}{-1}
\end{internallinenumbers}
\end{minipage}}
\let#3=\themylines}
\begin{document}

\CalcNumber{\lipsum[1]}{8cm}{\myx}

\myx

\CalcNumber{A}{8cm}{\myy}

\myy


\end{document}