Dynamic updates in Overleaf

How do you keep updated in your LaTeX document a number that changes every often in its original source?…

I was writing a document in @overleaf that included some numbers extracted from an online spreadsheet that was updated regularly. 馃У

I needed to keep my LaTeX document in sync with those shared spreadsheet values. But AFAIK there wasn't any option available neither in Overleaf nor in any other LaTeX package for implementing "dynamic update" behavior. So I created one 馃檪

First, we need to publish a link to the source spreadsheet so we can access the value of any cell through an endpoint like:
(Share it at least for read access. Then, publish it: File / Publish to the web)

https://spreadsheets.google.com/feeds/cells/1xhWskXv1qCDIHSAxSzEaQBeFKP1vfuR5ZLdx7nsgBg4/default/public/full/R3C3?alt=json

(R3C3 = Row 3, Column 3 = Row 3, Column C)

If you need further explanations about how to obtain the URL shown here, use this step-by-step guide:
https://www.freecodecamp.org/news/cjn-google-sheets-as-json-endpoint/)

Then, we need to define a LaTeX command to access the endpoint and insert the cell value from the spreadsheet in our LaTeX document. Something like

\get{https://spreadsheets.google.com/feeds/cells/1xhWskXv1qCDIHSAxSzEaQBeFKP1vfuR5ZLdx7nsgBg4/default/public/full/R3C3?alt=json}{XXX}

(The XXX value is the value by default)

We will define the \get command in our LaTeX document as follows:

But how can we instruct Overleaf to execute that \get command to access the JSON value from the endpoint and insert it online in our current document?

Well, we first need to know how to parse an Overleaf document programmatically.

Then we need to know how to search for the \get command in our LaTex document.

Internally, Overleaf uses the Ace editor

https://ace.c9.io/

Ace is an embeddable code editor written in JavaScript. It offers a simple yet complete JS API to access and manipulate the content of the current document.

Let's try to use the Ace API offered by Overleaf to get the number of lines of the current LaTeX document.

Open DevTools in Chrome (or the web console in Firefox) and run this script:

As you can see, we obtained the reference to Ace and calculated the number of lines of the current document programmatically (25, in our case)

Now, using the same API we are now in a good position to find the next occurrence of our \get command in the document:

Once our \get command is selected, we need to parse it and obtain the URL of the endpoint and the dynamic value of the cell (we will store it in the newValue variable)

Something like this:

Finally, we only need to replace the current \get command and value with the new value… and iterate, finding the next occurrence and repeating the process.

I have published a gist with the full source code 馃檪

let ace = document.querySelector(".ace_editor");
// ace.env.editor.session.getLength(); // number of lines
let previousRow = 0
let r = ace.env.editor.find('\\get\{(.*?)\}\{(.*?)\}',{
backwards: false,
wrap: false,
caseSensitive: false,
wholeWord: false,
regExp: true
});
while (r?.end.row >= previousRow){
previousRow = r.end.row
const original = ace.env.editor.getSelectedText();
const values = original.match(/\{.*?\}/g)
const jsonvalue = await fetch(values[0].substring(1, values[0].length-1))
const cell = await jsonvalue.json()
const newValue = parseFloat(cell.entry.content.$t)
const range = ace.env.editor.selection.getRange();
ace.env.editor.session.replace(range, `\get${values[0]}{${newValue}}`);
r = ace.env.editor.find('\\get\{(.*?)\}\{(.*?)\}',{
backwards: false,
wrap: false,
caseSensitive: false,
wholeWord: false,
regExp: true
});
}

Here, you can see the script in action. Hope it helps!

A link to the LaTeX document used in the video:

https://www.overleaf.com/read/nvqpgknvmbrj

Originally tweeted by juanan (@juanan) on 12 July, 2021.

Deja una respuesta

Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *

Este sitio usa Akismet para reducir el spam. Aprende c贸mo se procesan los datos de tus comentarios.