3

I want to include parts of a child document, specified by a range of line numbers, as LaTeX input, while producing useful SyncTeX information. It should also be possible to re-include lines already in the main document.


Example

Given input files

% -- main.tex
 ..:  ...
 20:  Before input.\par
 21:  \inputlines{2}{4}{child.tex}
 22:  After input.\par
 23:  Repeat: \inputlines{22}{22}{main.tex}
 ..:  ...

% -- child.tex
  1: 1 First line.\par
  2: 2 Second line.\par
  3: 3 Third line.\par
  4: 4 Fourth line.\par
  5: 5 Fifth line.\par

I want the output to contain

...
Before input.
2 Second line.
3 Third line.
4 Fourth line.
After input.
Repeat: After input.
...

and invoking inverse search on "2 second line." should actually direct the editor to the correct line in child.tex.


Existing partial solutions

Related question. In "\input only part of a file", a solution is provided, that does what I want except for SyncTeX support. As far as I can tell, that is an unfortunate side effect of processing a file with the \read mechanism.

Crucially, this solution is robust in situations containing multi-line constructs, such as multi-line \defs or the equation environment.

Package "listings". The command \lstinputlisting of the listings package provides options firstline and lastline, that perform the desired filtering, while providing SyncTeX support.

It is however specialized for including files in verbatim and I was unable to verify

  • How their filtering-by-line works, and
  • if it can be transferred to LaTeX input without breaking either multi-line constructs or SyncTeX.

Package "catchbetweentags". The catchfilebetweentags package provides a mechanism for including file contents marked explicitly. However, for my purposes requiring explicit %<*tag> ... %</tag> comments is undesirable, and SyncTeX information is lost anyway.


Purpose

I am researching options for this, in order to rewrite the apxproof package with SyncTeX support. Currently this package creates an auxiliary file, that is later included, thereby creating junk SyncTeX information, that points to the auxiliary file.

Reading files partially, if possible without losing SyncTeX support, would allow building the functionality on a different basis.

MWE with apxproof, demonstrating the problem

\makeatletter\input{filecontents.sty}\makeatother
\begin{filecontents*}{\jobname.child.tex}
This proof has its contents stored in a child document.
SyncTeX will correctly point to this file
but
\begin{itemize}
\item It doesn't fix the loss of precision in \verb|thmrep|.
\item With many proofs, the large number of child documents
      can become rather inconvenient.
\end{itemize}
\end{filecontents*}



\documentclass{article}
\usepackage{apxproof}
\usepackage{etoolbox}
\let\appendixprelim\relax % Prevent newpage before typesetting proofs.
\newtheoremrep{thm}{Theorem}
\preto\appendix{\noindent\hrulefill Appendix starts here}

\begin{document}

\section{Start}

\begin{thmrep}
This is a theorem, that will be repeated in the appendix.

SyncTeX sort of works here, for 

It does however point only to the end of the environment,
not to individual paragraphs.
\end{thmrep}

\begin{appendixproof}
This is the proof, which will be put into the appendix via \verb|\VerbatimOut| mechanism.

\textsf{apxproof} defers it to the appendix,
by writing it out to \verb|\jobname.axp|
and then \verb|\input|ing it in the appendix.

Sadly, this mechanism causes SyncTeX to consider
the auxiliary file \verb|\jobname.axp| to be
the source of the contents.
\end{appendixproof}

\begin{appendixproof}
\input{\jobname.child.tex}
\end{appendixproof}

\end{document}

Compiled Screenshot

6
  • For my purpose, not really (though I'll keep in in mind for other usecases). (a) For reimplementing/extending apxproof, the solution would have to be able to re-read from the main document too, which creates a bootstrapping problem. (b) Using such constructs, or environments to the same effect, would sabotage the overall usability, leaving the loss of SyncTeX information or workarounds like \begin{proof}\input{proof.123.inc}\end{proof} as lesser evil.
    – kdb
    Jun 27, 2018 at 7:56
  • @JohnKormylo As far as I can tell, storing tokens into macros discards the SyncTeX information.
    – kdb
    Jun 27, 2018 at 14:40
  • @JohnKormylo SyncTeX is the only reason for me to be looking into this actually. The apxproof package is quite useful, but its usability is hindered strongly by the loss of synctex support, so I was hoping to achieve the same behavior in some manner that preserves SyncTeX information.
    – kdb
    Jun 28, 2018 at 11:22
  • A complete MWE would be useful here. I'm wondering if a savebox might work. Jun 28, 2018 at 13:23
  • 1
    Whatever SyncTeX is supposed to do, it doesn't work on my system. Never mind. Jun 28, 2018 at 17:59

2 Answers 2

2

I found a solution, under the constraint that what one wants to re-read is delimited by an environment. Having no time to clean it up right now, I just post the raw example.

The work is done by the \InputPartialFile macro.

%% == filterfiles-selfreparse.tex
\documentclass[12pt]{article}
\usepackage{etoolbox}
\newenvironment{fold}{}{}

\makeatletter

\begin{document}

Line \the\inputlineno.
Line \the\inputlineno.
Line \the\inputlineno.

Line \the\inputlineno.
Line \the\inputlineno.
Line \the\inputlineno.

\newcount\startline
\startline=\inputlineno
\begin{fold}
First paragraph inside fold.

\ifcsname IPF@nesting\endcsname\the\IPF@nesting\fi

  \begin{fold}
  Stuff inside nested fold.
  \begin{equation}
  content...
  \end{equation}
  \end{fold}

Second paragraph inside fold = end of fold.

\end{fold}After fold, same line.
After fold, next line.


%% Must use line-skipping instead of \@gobble, because
%% \@gobble updates \inputlineno only after the first character
%% of the line has been lost.
\begingroup
\global\long\def\IPF@skipline#1{%
  \begingroup
  \catcode`\^^M=13\relax
  \IPF@skipline@b{#1}%
}
% next lines are whitespace-sensitive.
\catcode`\^^M=13
\global\long\def\IPF@skipline@b#1#2^^M{\endgroup#1}\endgroup

\def\InputPartialFile#1#2{
  %% Usage: \InputPartialFile{STARTLINE}{FILENAME}
  %%
  %% Read FILENAME from STARTLINE until a balanced \end{ENV} form.
  %% Technical limitation: Anything after the \end{..} on the same
  %% line will be included.
  %%
  %% Currently NOT nestable.
  %% 
  \begingroup
  \newcount\startline
  \startline=#1\relax
  \begingroup
  \long\def\@@gobble##1{\global\long\def\@@gobbled{##1}}
  \def\IPF@skip{%
    \ifnumcomp{\inputlineno+1}{<}{\startline}{%
      \IPF@skipline\IPF@skip
    }{%
      \endgroup
      \newcount\IPF@nesting
      \IPF@nesting=0
      \pretocmd{\begin}{%
        \advance\IPF@nesting by 1
      }{}{\errmessage{Failure to patch \string\begin}}%
      \apptocmd{\end}{%
        \advance\IPF@nesting by -1
        \ifnum\IPF@nesting=0
          \endinput
        \fi
      }{}{\errmessage{Failure to patch \string\end}}%
    }%
  }
  \ttfamily\noindent
  \expandafter\IPF@skip
  \@@input #2\relax
  \endgroup
  %\endgroup
}



\framebox[\linewidth]{\parbox{\linewidth}{
  \texttt{\string\InputPartialFile\{16\}\{filterfiles-selfreparse\}}
  \par\hrulefill\par
  \InputPartialFile{16}{filterfiles-selfreparse}
  \par\hrulefill\par
  \texttt{\string\InputPartialFile\{17\}\{\string\jobname\}}
  \par\hrulefill\par
  \InputPartialFile{17}{\jobname}
}}


\end{document}
1
  • Idea summary: the solution \input the file, but use some TeX macro to "skip through" the first part of the content, and modify the \end macro to detect when the environment terminates and execute \endinput.
    – user202729
    Jan 27 at 11:17
0

With LuaLaTeX, using the callback it's possible to do this. See In LuaLaTeX, how do I pass the content of an environment to Lua verbatim? for other examples.

%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage[paper=a4paper,margin=0.6cm]{geometry}
\usepackage{currfile}

\iffalse
line 1

line 2

line 3
\fi

\directlua{
saved_synctex_tag=tex.get_synctex_tag()
function readbuf(buf)
    if not (saved_synctex_tag==nil) then
        --[[ this code should only be executed once after the \\input ]]
        tex.set_synctex_tag(saved_synctex_tag)
        tex.set_synctex_no_files(0)
        saved_synctex_tag=nil
    end
    if 7<=tex.inputlineno and tex.inputlineno<=11 then
        return nil
    else
        return ""
    end
end
}

\begin{document}

start

\directlua{
    tex.set_synctex_no_files(1)
    saved_synctex_tag=tex.get_synctex_tag()
    luatexbase.add_to_callback('process_input_buffer', readbuf, 'readbuf')
    }\input{\currfilename}\directlua{luatexbase.remove_from_callback('process_input_buffer', 'readbuf')}

end

\end{document}

The \iffalse ... \fi is just for demonstration. There's no need for commands there, line number is sufficient.

Both forward and backward search works well. If you don't need the forward search outside the subfile, it's possible to remove the synctex parts.


Regarding the forward search, the problem here is that if there are multiple tag that corresponds to the same file, the synctex utility will only output the entry that corresponds to the last tag (read man 5 synctex and other sources for details of the synctex file format).

To fix it, it may be possible to use tex.set_synctex_tag in LuaTeX to be the same as the tag of the parent file, and do not record the tag entry of the subfile (with set_synctex_no_files).

Also make sure that the \input is on the same line as the \directlua, otherwise the one-time call will be executed before \input.

See also https://tex.stackexchange.com/a/632368/250119 for an example of the usage of the former function.

0

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.