How to implement \text in plain tex?

Really in plain you just have to use

\hbox{hello world}

in amsmath (or more exactly amstext) \text is defined to use \mathchoice and use different size text is subscripts etc, however plain tex has no real font size changing commands so there is, by default, nothing comparable you can do. If you restrict to \rm then that font is set up at different sizes in \fam0 so you could do

\def\textrm#1{\mathchoice
{\hbox{\the\textfont0 #1}}
{\hbox{\the\textfont0 #1}}
{\hbox{\the\scriptfont0 #1}}
{\hbox{\the\scriptscriptfont0 #1}}}


$$\textrm{one two} x^{\textrm{one two}^{\textrm{one two}}}$$

\bye

enter image description here


You can use opmac (which I recommend anyway if you insist in using plain TeX):

\input opmac

\def\text#1{%
  \relax
  \ifmmode
    \mathchoice
      {\hbox{#1}}
      {\hbox{#1}}
      {\hbox{\typoscale[700/]\relax#1}}
      {\hbox{\typoscale[500/]\relax#1}}%
  \else
    \hbox{#1}%
  \fi
}
$$
a\text{a}_{a\text{a}_{a\text{a}}}
$$
$$
a+b=b+a\text{ is a {\it nice\/} property}
$$
$$
\scriptstyle a+b=b+a\text{ is a {\it nice\/} property}
$$
$$
\scriptscriptstyle a+b=b+a\text{ is a {\it nice\/} property}
$$

\bye

enter image description here


Just for the fun of it, let me try describing what your macros do.

\def\text#1{\begingroup\rm\testing#1\endtest}
{\escapechar=-1\xdef\endtest{\string\\endtest}}
\def\testing#1#2{\ifx#2\endtest\let\next=\endgroup\else\let\next=\testing\fi%
{\catcode`\|=10\ifcat#1|\hskip.5em\else#1\fi}\next #2}

First \text is defined to absorb its argument and return the token list

\begingroup\rm\testing<argument>\endtesting

The macro \testing is defined to have two arguments. If the second argument is \endtest, the control sequence \next is defined to be \endgroup else it is defined to be \testing, which starts up a recursion. Then

{\catcode`\|=10\ifcat#1|\hskip.5em\else#1\fi}

is done, where #1 stands for the first token (or contents of braced group) following \testing. The test \ifcat#1| will not succeed if #1 is a space for two reasons: spaces are ignored when TeX is looking for an undelimited argument, so #1 will never be a space token; second reason, the test will succeed when #1 is a single token of category code 12, which is the category code of | at definition's time.

Thus you get a space when a character such as . (catcode 12) follows (and the character is ignored), or the character otherwise, if it is a letter. If #1 is the contents of a braced group, then, well, anything can happen. Finally \next is executed, and #2 is reinserted. This is the reason for “endtest” to appear at the end.

Recall that when an argument is absorbed, category codes are frozen, so the setting \catcode`\|=10 does nothing at all.

A recursion without the “termination” problem is obtained by adding two terminators.

% generic terminators
\def\TerminatorA{\TerminatorA}
\def\TerminatorB{\TerminatorB}

\def\boldenas#1{\boldenasRecurse#1\TerminatorA\TerminatorB}
\def\boldenasRecurse#1#2#3\TerminatorB{%
  \boldenasDo{#1}%
  \ifx#2\TerminatorA
    \let\next\boldenasEnd
  \else
    \let\next\boldenasRecurse
  \fi
  \next#2#3\TerminatorB
}
\def\boldenasDo#1{%
  \ifx #1a%
    {\bf a}%
  \else
    #1%
  \fi
}
\def\boldenasEnd#1\TerminatorB{}


\boldenas{abracadabra}

\bye

This is not safe against #1 being empty (we're tough plain TeX users, after all). Spaces will be gobbled for the reason I explained earlier and braced groups will produce chaos. But, hey, we're doing theory!

Note that the \let instructions can be avoided:

% generic terminators
\def\TerminatorA{\TerminatorA}
\def\TerminatorB{\TerminatorB}
% syntactic sugar
\long\def\firstoftwo#1#2{#1}
\long\def\secondoftwo#1#2{#2}

\def\boldenas#1{\boldenasRecurse#1\TerminatorA\TerminatorB}
\def\boldenasRecurse#1#2#3\TerminatorB{%
  \boldenasDo{#1}%
  \ifx#2\TerminatorA
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  \boldenasEnd\boldenasRecurse#2#3\TerminatorB
}
\def\boldenasDo#1{%
  \ifx #1a%
    {\bf a}%
  \else
    #1%
  \fi
}
\def\boldenasEnd#1\TerminatorB{}


\boldenas{abracadabra}

\bye