davidcarlisle / latexcgi

LaTeX server via perl cgi script, developed for learnlatex.org
https://davidcarlisle.github.io/latexcgi/
MIT License
32 stars 3 forks source link

Add a way to help to guess what is missing in snippets/document fragments #8

Closed dbitouze closed 1 year ago

dbitouze commented 2 years ago

The very nice trick that guesses and adds what is missing in snippets/document fragments often works, e.g. with:

https://texlive.net/run?\textcolor{red}{foobar}

but sometimes fails, e.g. with:

https://texlive.net/run?\begin{wrapfigure}[12]{r}[34pt]{5cm}foobar\end{wrapfigure}

It would be nice to have a way to provide (as a special “magic” comment?) what is needed to add in the preambles of the snippets/document fragments in order to make them work.

davidcarlisle commented 2 years ago

I'm not sure I'd want to have a comment syntax for this, if you have to add a comment saying "add wrapfig" you may as well write the preamble, however you can easily support more packages, after loading runlatex.js have

<script>
var packageregex = [
    [ /\\includegraphics/,                    "\\usepackage[demo]{graphicx}\n"],
    [ /\\begin{equation|align|gather|flalign/,"\\usepackage{amsmath}\n"       ],
    [ /tikz|pgf/,                             "\\usepackage{tikz}\n"          ],
    [ /fancy/,                                "\\usepackage{fancyhdr}\n"      ],
    [ /addplot|axis/,                         "\\usepackage{pgfplots}\n"      ],
    [ /hyper|href|bookmark|\\url/,            "\\usepackage{hyperref}\n"      ],
    [ /\\newcolumntype/,                      "\\usepackage{array}\n"         ],
    [ /listing/,                              "\\usepackage{listings}\n"      ],
    [ /\\blind/,                              "\\usepackage{blindtext}\n"     ],
    [ /\\lipsum/,                             "\\usepackage{lipsum}\n"        ],
    [ /color/,                                "\\usepackage{xcolor}\n"        ],
    [ /pspicture/,                            "\\usepackage{pstricks}\n"      ]
];

</script>

that is the definition copied from the code. in each case the first entry is a regular expression between /../ and the second entrey is a preamble line to add if any line in the fragment matches. Add more lines as you wish....

dbitouze commented 2 years ago

I'm not sure I'd want to have a comment syntax for this, if you have to add a comment saying "add wrapfig" you may as well write the preamble,

In a FAQ, it is often convenient to focus just on the relevant snippet code and to not distract with the whole code of a complete example.

however you can easily support more packages, after loading runlatex.js have

<script>
var packageregex = [
    [ /\\includegraphics/,                    "\\usepackage[demo]{graphicx}\n"],
    [ /\\begin{equation|align|gather|flalign/,"\\usepackage{amsmath}\n"       ],
    [ /tikz|pgf/,                             "\\usepackage{tikz}\n"          ],
    [ /fancy/,                                "\\usepackage{fancyhdr}\n"      ],
    [ /addplot|axis/,                         "\\usepackage{pgfplots}\n"      ],
    [ /hyper|href|bookmark|\\url/,            "\\usepackage{hyperref}\n"      ],
    [ /\\newcolumntype/,                      "\\usepackage{array}\n"         ],
    [ /listing/,                              "\\usepackage{listings}\n"      ],
    [ /\\blind/,                              "\\usepackage{blindtext}\n"     ],
    [ /\\lipsum/,                             "\\usepackage{lipsum}\n"        ],
    [ /color/,                                "\\usepackage{xcolor}\n"        ],
    [ /pspicture/,                            "\\usepackage{pstricks}\n"      ]
];

</script>

that is the definition copied from the code. in each case the first entry is a regular expression between /../ and the second entrey is a preamble line to add if any line in the fragment matches. Add more lines as you wish....

OK but:

  1. too bad everybody will extend this packageregex variable each on his own: wouldn't be possible to centralize this script that would be loaded thanks to <script src="[https://..."></script>?
  2. sometimes, what has to be added in the preamble isn't a \usepackage command, but some \@onlypreamble command.
davidcarlisle commented 2 years ago

too bad everybody will extend this packageregex variable each on his own: wouldn't be possible to centralize this script that would be loaded thanks to ?

No sorry, I think this is a feature, you can customise the heuristic to the packages discussed in your faq. If I started collecting a central file, I would have no criterion for accepting or rejecting lines and could end up with regex matching every command defined and adding a suitable package line for every package from ctan. This would be a maintenance nightmare for me and slow down processing for everyone.

In fact most sites (including the original at learnlatex.org) host copies of the javascript on that site rather than reference the github pages view here and have other local customisaions for buttons and styling, so a local list of package guesses is quite natural.

sometimes, what has to be added in the preamble isn't a \usepackage command, but some \@onlypreamble command.

that is not a problem, the string in the second entry in each case is added if the correspoding regex matches, it can be any string at all, just happens to be \usepackage in all the cases here.

dbitouze commented 2 years ago

too bad everybody will extend this packageregex variable each on his own: wouldn't be possible to centralize this script that would be loaded thanks to ?

No sorry, I think this is a feature, you can customise the heuristic to the packages discussed in your faq. If I started collecting a central file, I would have no criterion for accepting or rejecting lines and could end up with regex matching every command defined and adding a suitable package line for every package from ctan. This would be a maintenance nightmare for me and slow down processing for everyone.

OK.

In fact most sites (including the original at learnlatex.org) host copies of the javascript on that site rather than reference the github pages view here and have other local customisaions for buttons and styling, so a local list of package guesses is quite natural.

OK.

sometimes, what has to be added in the preamble isn't a \usepackage command, but some @onlypreamble command.

that is not a problem, the string in the second entry in each case is added if the correspoding regex matches, it can be any string at all, just happens to be \usepackage in all the cases here.

I don't understand how to proceed e.g. in the following case:

\documentclass{article}
\usepackage{amsopn}
\DeclareMathOperator*{\Lim}{Lim}
\begin{document}
$\Lim f$
\end{document}

if I want to display only a snippet exposing only \DeclareMathOperator*{\Lim}{Lim} and $\Lim f$: \usepackage{amsopn} could be guessed from \DeclareMathOperator* but this latter command cannot be in the document body.

davidcarlisle commented 2 years ago

@dbitouze ah no sorry you can't do that, that is essentially two fragments a preamble fragment (where \DeclareMathOperator infers amsopn (or more likely amsmath I don't think I have ever used amsopn directly) and a document fragment, \Lim

that would probably be possible with some magic % end of preamble comment to separate the parts but I'm not going to add that in the core code. By design the fragment guesser is brutally simplistic, it does not parse at all or even distingish comments. \color triggers xcolor package but so does % this document does not use color (I made the regex match color rather than \color so \textcolor, \fcolorbox, \foo[color=red],... all matched.) It is a very simple regex search over the whole input, bounding the search to specific regions wouldn't be hard in principle but would require a lot more code than the current version.

davidcarlisle commented 2 years ago

No promises, but I had a thought about this, re-opening so I don't forget

davidcarlisle commented 2 years ago

@dbitouze try

https://davidcarlisle.github.io/latexcgi/test-sk.html#begindocument

I added a simple check so it doesn't add \begin{document} if that text is there already so a fragment

\DeclareMathOperator*{\Lim}{Lim}
\begin{document}
$\Lim f$

works

davidcarlisle commented 2 years ago

@dbitouze locally setting packageregex does work but it's not currently documented, it is with the other regex that are really part of the internal code.

I am thinking of documenting it and moving it to the public runlatex configuration object so its name would be

runlatex.packageregex

But otherwise work as now. This would be a breaking change if anyone is currently using the current name, but I suspect there are no users doing that, but I'll check with Stefan who is the main user, other than learnlatex.

dbitouze commented 2 years ago

@dbitouze try

https://davidcarlisle.github.io/latexcgi/test-sk.html#begindocument

Works nicely, many thanks! :smile:

I added a simple check so it doesn't add \begin{document} if that text is there already so a fragment

\DeclareMathOperator*{\Lim}{Lim}
\begin{document}
$\Lim f$

IMHO, such (seemingly) unbalanced code may look erroneous. What about a regexp looking for a string such as a comment like % End of preamble instead of \begin{document}? At least, it would be nice for the delimiter string to be customizable.

davidcarlisle commented 2 years ago

@dbitouze I knew you were going to say that:-) This version is a lot simpler as it isn't inserting anything: it is just a simple if().. around the existing insertion before the fragment, to not add \begin{document} in a case where adding it would generate an error.

Currently the supplied fragment is never edited, just has code added before and after. So I fear that's as far as I want to go in the core code, but anyone looking at the diff of the last commit who knows any javascript could extend if needed. Note it needs no special server setup to host a modified (or unmodified) copy of runlatex.js All the processing, guessing of preambles etc is happning in the users browser and is quite separate from the server running the tex process.

davidcarlisle commented 2 years ago

I moved the regex array (will adjust the documentation later) but

https://davidcarlisle.github.io/latexcgi/test-sk.html#siunitx

shows an example needing siunitx the page adds that via

      runlatex.packageregex.push(
      [/\\qty *[\[{]/, "\\usepackage{siunitx}\n"]
      );
dbitouze commented 2 years ago

I moved the regex array (will adjust the documentation later) but

https://davidcarlisle.github.io/latexcgi/test-sk.html#siunitx

shows an example needing siunitx the page adds that via

      runlatex.packageregex.push(
    [/\\qty *[\[{]/, "\\usepackage{siunitx}\n"]
      );

Thanks! But, sorry, I don't see the benefit over the script you provided here.

davidcarlisle commented 2 years ago

Thanks! But, sorry, I don't see the benefit over the script you provided

@dbitouze it is exactly the same except I renamed the array from packageregex to runlatex.packageregex

Having a configuration via an undocumented global array is bad form even when it works, so I moved it to be part of the documented runlatex configuration object, and added documentation at

https://davidcarlisle.github.io/latexcgi/#the-runlatex-configuration-object

(New last item in the list)

But it is just a rename, the code is identical.

davidcarlisle commented 1 year ago

I guess I did as much as I could here (or at least as much as I wanted to do) closing. thanks for the feature request