3

Suppose person A writes a short bit of TeX code, and sends it to person B for inclusion as part of a larger document. The snippet written by A doesn't use anything fancy: no cross-references, citations, sectioning, footnotes, etc. etc. But it has math, of course, and minimal text formatting commands like bold, italics, enumerated lists, maybe tables, etc.

The problem is that A and B use different flavors of TeX. I believe that A uses Plain TeX and B uses LaTeX, then usually B can just paste A's code in and it will work, since most of the text-formatting commands in Plain TeX (e.g. {\bf bold}) are actually TeX primitives and hence also available in LaTeX even if not the "recommended" style.

If A uses LaTeX and B uses Plain TeX there is more of a problem, since for instance \textbf{bold} doesn't exist in Plain TeX. But of course in this case, B can just define a simple version of it herself. My question is whether I can save B this work? Where can I find a short, quick and dirty collection of macro definitions that a Plain TeX user can paste at the top of her document that will enable her to paste in simple fragments of LaTeX, using no more than basic text formatting commands and (say) list and tabular environments, and have them come out looking at least vaguely reasonable? Obviously if the LaTeX code uses anything fairly complicated, then there is no answer to this (short of pasting in or reimplementing all of LaTeX), but it seems that for very simple code it should be possible, and maybe someone has done it before.

  • For text formatting only, plnfss should work. – texnezio Sep 14 '17 at 22:20
  • @erreka The documentation of plnfss is not very helpful, but poking through the files I don't see any definitions of latex-like macros? – Mike Shulman Sep 14 '17 at 22:28
  • Supported Commands \rmfamily \sffamily \ttfamily \mdseries \bfseries \upshape \itshape \slshape \scshape \normalfont \textrm \textsf \texttt \textmd \textbf \textup \textit \textsl \textsc \rm \sf \tt \md \bf \up \it \sl \sc What is missing?: - size commands: \large, \huge etc. Use \fontsize{20pt} instead. - scaling - math support is poor – texnezio Sep 14 '17 at 22:36
  • 4
    note \bf is not a tex primitive (and not defined by default in latex) so even using plain in latex is not always guaranteed. The other direction is just as hard as you want to make it, \mathbf is easy to define, an ams alignment less so. – David Carlisle Sep 14 '17 at 22:54
  • @DavidCarlisle -- since amsmath is derived from ams-tex there might be some hope there, but the thought of trying to implement tabular in plain tex strikes terror in me. there are some list-like features in ams-tex (roster), but no automatic numbering. i'm not familiar enough with eplain to know whether that holds promise. – barbara beeton Sep 15 '17 at 2:53
2

You can always just copy the definitions. The file miniltx.tex will help a bit (this already allows latex colour and graphics commands in plain, and defines some internal latex tools, but it does not help a lot with tabular. The file below adds tabular, just the basic version not extended versions from array package or tabularx etc, also I used \Lbegin and \Lend to avoid clashing with the \end primitive as used by \bye.

enter image description here

\catcode`\@=11
\input miniltx

\def\@ignorefalse{\global\let\if@ignore\iffalse}
\def\@ignoretrue {\global\let\if@ignore\iftrue}
\@ignorefalse
\let\ignorespacesafterend\@ignoretrue
\let\@typeset@protect\relax
\def\set@display@protect{\let\protect\string}
\def\set@typeset@protect{\let\protect\@typeset@protect}
\def\protected@edef{%
   \let\@@protect\protect
   \let\protect\@unexpandable@protect
   \afterassignment\restore@protect
   \edef
}
\def\protected@xdef{%
   \let\@@protect\protect
   \let\protect\@unexpandable@protect
   \afterassignment\restore@protect
   \xdef
}
\def\unrestored@protected@xdef{%
   \let\protect\@unexpandable@protect
   \xdef
}
\def\restore@protect{\let\protect\@@protect}
\set@typeset@protect

\def\@endparenv{%
  \addpenalty\@endparpenalty\addvspace\@topsepadd\@endpetrue}
\def\@doendpe{\@endpetrue
     \def\par{\@restorepar
              \clubpenalty\@clubpenalty
              \everypar{}\par\@endpefalse}\everypar
               {{\setbox\z@\lastbox}%
                \everypar{}\@endpefalse}}
\newif\if@endpe
\@endpefalse

\def\Lbegin#1{%
  \@ifundefined{#1}%
    {\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
    {\def\reserved@a{\def\@currenvir{#1}%
     \edef\@currenvline{\on@line}%
     \csname #1\endcsname}}%
  \@ignorefalse
  \begingroup\@endpefalse\reserved@a}
\def\Lend#1{%
  \csname end#1\endcsname\@checkend{#1}%
  \expandafter\endgroup\if@endpe\@doendpe\fi
  \if@ignore\@ignorefalse\ignorespaces\fi}
\def\@checkend#1{\def\reserved@a{#1}\ifx
      \reserved@a\@currenvir \else\@badend{#1}\fi}
\let\@currenvline\@empty

\def\extracolsep#1{\tabskip #1\relax}
\def\array{\let\@acol\@arrayacol \let\@classz\@arrayclassz
 \let\@classiv\@arrayclassiv
 \let\\\@arraycr\let\@halignto\@empty\@tabarray}
\def\endarray{\crcr\egroup\egroup}
\def\endtabular{\crcr\egroup\egroup $\egroup}
\expandafter \let \csname endtabular*\endcsname = \endtabular
\def\tabular{\let\@halignto\@empty\@tabular}
\@namedef{tabular*}#1{%
 \setlength\dimen@{#1}%
   \edef\@halignto{to\the\dimen@}\@tabular}
\def\@tabular{\leavevmode \hbox \bgroup $\let\@acol\@tabacol
   \let\@classz\@tabclassz
   \let\@classiv\@tabclassiv \let\\\@tabularcr\@tabarray}
\def\@tabarray{\m@th\@ifnextchar[\@array{\@array[c]}}
\def\@array[#1]#2{%
  \if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi
  \bgroup
  \setbox\@arstrutbox\hbox{%
    \vrule \@height\arraystretch\ht\strutbox
           \@depth\arraystretch \dp\strutbox
           \@width\z@}%
  \@mkpream{#2}%
  \edef\@preamble{%
    \ialign \noexpand\@halignto
      \bgroup \@arstrut \@preamble \tabskip\z@skip \cr}%
  \let\@startpbox\@@startpbox \let\@endpbox\@@endpbox
  \let\tabularnewline\\%
    \let\par\@empty
    \let\@sharp##%
    \set@typeset@protect
    \lineskip\z@skip\baselineskip\z@skip
    \ifhmode \@preamerr\z@ \@@par\fi
    \@preamble}
\def\@arraycr{%
  ${\ifnum0=`}\fi\@ifstar\@xarraycr\@xarraycr}
\def\@xarraycr{\@ifnextchar[\@argarraycr{\ifnum0=`{\fi}${}\cr}}
\def\@argarraycr[#1]{%
  \ifnum0=`{\fi}${}\ifdim #1>\z@ \@xargarraycr{#1}\else
   \@yargarraycr{#1}\fi}
\let\tabularnewline\relax
\def\@tabularcr{%
  {\ifnum0=`}\fi\@ifstar\@xtabularcr\@xtabularcr}
\def\@xtabularcr{\@ifnextchar[\@argtabularcr{\ifnum0=`{\fi}\cr}}
\def\@argtabularcr[#1]{%
  \ifnum0=`{\fi}%
    \ifdim #1>\z@
      \unskip\@xargarraycr{#1}%
    \else
      \@yargarraycr{#1}%
    \fi}
\def\@xargarraycr#1{\@tempdima #1\advance\@tempdima \dp \@arstrutbox
   \vrule \@height\z@ \@depth\@tempdima \@width\z@ \cr}
\def\@yargarraycr#1{\cr\noalign{\vskip #1}}
\long\def\multicolumn#1#2#3{\multispan{#1}\begingroup
  \@mkpream{#2}%
  \def\@sharp{#3}\set@typeset@protect
  \let\@startpbox\@@startpbox\let\@endpbox\@@endpbox
  \@arstrut \@preamble\hbox{}\endgroup\ignorespaces}
\def\@xexnoop #1\@@{}
\def\@expast#1{\@xexpast #1*0x\@@}
\def\@xexpast#1*#2#3#4\@@{%
  \edef\reserved@a{#1}%
  \@tempcnta#2\relax
  \ifnum\@tempcnta>\z@
    \@whilenum\@tempcnta>\z@\do
       {\edef\reserved@a{\reserved@a#3}\advance\@tempcnta \m@ne}%
    \let\reserved@b\@xexpast
  \else
    \let\reserved@b\@xexnoop
  \fi
  \expandafter\reserved@b\reserved@a #4\@@}
\newif\if@firstamp
\def\@addamp{%
  \if@firstamp
    \@firstampfalse
  \else
    \edef\@preamble{\@preamble &}%
  \fi}
\def\@arrayacol{\edef\@preamble{\@preamble \hskip \arraycolsep}}
\def\@tabacol{\edef\@preamble{\@preamble \hskip \tabcolsep}}
\def\@ampacol{\@addamp \@acol}
\def\@acolampacol{\@acol\@addamp\@acol}
\def\@mkpream#1{\@firstamptrue\@lastchclass6
  \let\@preamble\@empty
  \let\protect\@unexpandable@protect
  \let\@sharp\relax
  \let\@startpbox\relax\let\@endpbox\relax
  \@expast{#1}%
  \expandafter\@tfor \expandafter
    \@nextchar \expandafter:\expandafter=\reserved@a\do
       {\@testpach\@nextchar
    \ifcase \@chclass \@classz \or \@classi \or \@classii \or \@classiii
      \or \@classiv \or\@classv \fi\@lastchclass\@chclass}%
  \ifcase \@lastchclass \@acol
      \or \or \@preamerr \@ne\or \@preamerr \tw@\or \or \@acol \fi}
\def\@arrayclassz{\ifcase \@lastchclass \@acolampacol \or \@ampacol \or
   \or \or \@addamp \or
   \@acolampacol \or \@firstampfalse \@acol \fi
\edef\@preamble{\@preamble
  \ifcase \@chnum
     \hfil$\relax\@sharp$\hfil \or $\relax\@sharp$\hfil
    \or \hfil$\relax\@sharp$\fi}}
\def\@tabclassz{%
  \ifcase\@lastchclass
    \@acolampacol
  \or
    \@ampacol
  \or
  \or
  \or
    \@addamp
  \or
    \@acolampacol
  \or
    \@firstampfalse\@acol
  \fi
  \edef\@preamble{%
    \@preamble{%
      \ifcase\@chnum
        \hfil\ignorespaces\@sharp\unskip\hfil
      \or
        \hskip1sp\ignorespaces\@sharp\unskip\hfil
      \or
        \hfil\hskip1sp\ignorespaces\@sharp\unskip
      \fi}}}
\def\@classi{%
  \ifcase\@lastchclass
    \@acol\@arrayrule
  \or
    \@addtopreamble{\hskip \doublerulesep}\@arrayrule
  \or
  \or
  \or
    \@arrayrule
  \or
    \@acol\@arrayrule
  \or
    \@arrayrule
  \fi}
\def\@classii{%
  \ifcase\@lastchclass
  \or
    \@addtopreamble{\hskip .5\arrayrulewidth}%
  \fi}
\def\@classiii{\ifcase \@lastchclass \@acolampacol \or
   \@addamp\@acol \or
   \or \or \@addamp \or
   \@acolampacol \or \@ampacol \fi}
\def\@tabclassiv{\@addtopreamble\@nextchar}
\def\@arrayclassiv{\@addtopreamble{$\@nextchar$}}
\def\@classv{\@addtopreamble{\@startpbox{\@nextchar}\ignorespaces
\@sharp\@endpbox}}
\def\@addtopreamble#1{\edef\@preamble{\@preamble #1}}
\newcount\@chclass
\newcount\@lastchclass
\newcount\@chnum
\newdimen\arraycolsep
\newdimen\tabcolsep
\newdimen\arrayrulewidth
\newdimen\doublerulesep
\def\arraystretch{1}    % Default value.
\newbox\@arstrutbox
\def\@arstrut{%
  \relax\ifmmode\copy\@arstrutbox\else\unhcopy\@arstrutbox\fi}
\def\@arrayrule{\@addtopreamble{\hskip -.5\arrayrulewidth
   \vrule \@width \arrayrulewidth\hskip -.5\arrayrulewidth}}
\def\@testpach#1{\@chclass \ifnum \@lastchclass=\tw@ 4 \else
    \ifnum \@lastchclass=3 5 \else
     \z@ \if #1c\@chnum \z@ \else
                              \if #1l\@chnum \@ne \else
                              \if #1r\@chnum \tw@ \else
          \@chclass \if #1|\@ne \else
                    \if #1@\tw@ \else
                    \if #1p3 \else \z@ \@preamerr 0\fi
  \fi  \fi  \fi  \fi  \fi  \fi
\fi}
\def\hline{%
  \noalign{\ifnum0=`}\fi\hrule \@height \arrayrulewidth \futurelet
   \reserved@a\@xhline}
\def\@xhline{\ifx\reserved@a\hline
               \vskip\doublerulesep
               \vskip-\arrayrulewidth
             \fi
      \ifnum0=`{\fi}}
\def\vline{\vrule \@width \arrayrulewidth}
\def\cline#1{\@cline#1\@nil}
\def\@cline#1-#2\@nil{%
  \omit
  \@multicnt#1%
  \advance\@multispan\m@ne
  \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi
  \@multicnt#2%
  \advance\@multicnt-#1%
  \advance\@multispan\@ne
  \leaders\hrule\@height\arrayrulewidth\hfill
  \cr
  \noalign{\vskip-\arrayrulewidth}}
\def\multispan{\omit\@multispan}
\def\@multispan#1{%
  \@multicnt#1\relax
  \loop\ifnum\@multicnt>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\@multicnt\m@ne}

\def\@startpbox#1{\vtop\bgroup \setlength\hsize{#1}\@arrayparboxrestore}
\def\@endpbox{\@finalstrut\@arstrutbox\par\egroup\hfil}
\let\@@startpbox=\@startpbox
\let\@@endpbox=\@endpbox


\catcode`\@=12

\tabcolsep 6pt

aaaaaaaaaaa

\Lbegin{tabular}[c]{lll}

aaa&bbb&ccc\\
1&2&3\\
\Lend{tabular}


\bye
  • Thanks! What about enumerate and itemize? – Mike Shulman Sep 15 '17 at 10:16
  • @MikeShulman you do the same , add an itemize environment then add more and more code copied from latex.ltx until the undefined command errors go away but it's really not a good idea, by then you will have copied (literally) half the source of latex into a context where it's never been tested and it will sort of work in simple cases and fail in others and just using the same format for shared documents (hopefully a format that is designed for making documents not just a minimal format designed a a book example) makes much more sense. – David Carlisle Sep 15 '17 at 10:41
  • @MikeShulman you can input all of latex.ltx into plain tex and then use all of latex commands in plain if you really want to do that, I have a link.... tex.stackexchange.com/a/91050/1090 – David Carlisle Sep 15 '17 at 10:44
  • Okay. I had hoped that someone would have solved this problem already, at least for lists. Of course the latex list environments are doing all sorts of fancy things, but it seems like it should be straightforward to just translate them into some code that does nothing but prefix a bunch of lines by bullets or incremented numbers. – Mike Shulman Sep 15 '17 at 15:47
  • 1
    @erreka easier still to use latex. – David Carlisle Sep 18 '17 at 17:58
2

This is how I interpret the remaining part of the question: you would like to paste something like the following text:

\begin{enumerate}
\item January
\item February
\item March
\end{enumerate}

into a plain TeX document, and get something that vaguely looks like an enumerated list.

The following is one way to solve it.

First, look up how enumerated lists are input, in some macro package available in plain TeX (or implement your own). For example, this is how eplain does it:

\input eplain
\numberedlist
\li January
\li February
\li March
\endnumberedlist
\bye

eplain numberedlist

And this is how opmac does it:

\input opmac
\begitems \style n
* January
* February
* March
\enditems
\bye

opmac begitems style n

Next, do whatever hacking is necessary to turn that LaTeX syntax into the corresponding plain-TeX-with-macros input. For example, using eplain (note my macros can probably be improved):

\input eplain
\def\begin#1{
    \def\tmpenumerate{enumerate}
    \def\tmpitemize{itemize}
    \def\tmparg{#1}
    \ifx\tmparg\tmpenumerate
        \bgroup\def\item{\li}\numberedlist
        % May want to implement error-checking here
        \def\end##1{\endnumberedlist\egroup}
    \else
      \ifx\tmparg\tmpitemize
        \bgroup\def\item{\li}\unorderedlist
        \def\end##1{\endunorderedlist\egroup}
      \else
        \message{Unsupported environment #1}
      \fi
    \fi
}

\begin{enumerate}
\item January
\item February
\item March
\end{enumerate}

\begin{itemize}
\item April
\item May
\item June
\end{itemize}

\bye

Here, we have pasted the LaTeX snippets \begin{enumerate} … \end{enumerate} and \begin{itemize} … \end{itemize} into a plain TeX document, and got reasonable lists in the output:

eplain plus hack

Of course you'll need to come up with similar definitions for every environment you use, and you'll need to do more hackery if you want to support more elaborate syntax like the optional arguments of enumerate and so on. But you said

For my purposes, I would be happy with an answer that could deal with both itemize and enumerate simultaneously in a very bare-bones way like that.

and this is certainly very bare-bones. :-)

  • Great; this is the sort of thing I wanted! – Mike Shulman Sep 20 '17 at 6:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.