Skip to content

Commit 47eae1d

Browse files
authored
Support Tectonic engine and execute user-customizable command sequence (#245)
1 parent 732b86b commit 47eae1d

File tree

3 files changed

+106
-27
lines changed

3 files changed

+106
-27
lines changed

README.md

+49-1
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,16 @@ and see the block like this in the output
8181

8282
## Customization
8383

84-
The extension defaults to running `xelatex` on the server.
84+
The extension defaults to running the `xelatex` engine on the server.
8585
This command may be customized (e.g., to use `pdflatex` instead) by customizing
8686
your `jupyter_notebook_config.py` file:
8787

8888
```python
8989
c.LatexConfig.latex_command = 'pdflatex'
9090
```
9191

92+
The above configuration will compile a LaTeX document using the common predefined flags and options such as `-interaction` `-halt-on-error`, `-file-line-error`, `-synctex`. For more control over the command sequence, check the Manual Command Arguments configuration.
93+
9294
The extension defaults to running `bibtex` for generating a bibliography
9395
if a `.bib` file is found. You can also configure the bibliography command
9496
by setting
@@ -97,13 +99,59 @@ by setting
9799
c.LatexConfig.bib_command = '<custom_bib_command>'
98100
```
99101

102+
_New in 4.2.0_: `BibTeX` compilation is skipped if the following conditions are present:
103+
104+
- `c.LatexConfig.disable_bibtex` is explicitly set to `True` in the `jupyter_notebook_config.py` file
105+
- There are no .bib files found in the folder
106+
100107
To render references (`\ref{...}`), such as equation or chapter numbers, you would
101108
need to compile in multiple passes by setting
102109

103110
```python
104111
c.LatexConfig.run_times = 2
105112
```
106113

114+
_New in 4.2.0_: Manual Compile Command
115+
For more advanced customizations, a complete command sequence can be specified using the `manual_cmd_args` configuration in the `jupyter_notebook_config.py` file. This allows to define the exact command and use options the extension will finally execute:
116+
117+
```python
118+
c.LatexConfig.manual_cmd_args = [
119+
'lualatex', # Specify the LaTeX engine (e.g., lualatex, pdflatex)
120+
'-interaction=nonstopmode', # Continue compilation without stopping for errors
121+
'-halt-on-error', # Stop compilation at the first error
122+
'-file-line-error', # Print file and line number for errors
123+
'-shell-escape', # Enable shell escape
124+
'-synctex=1', # Enable SyncTeX for editor synchronization
125+
'{filename}.tex' # Placeholder for the input file name
126+
]
127+
```
128+
129+
The only supported placeholder in the manual compile command is `{filename}`. It will be replaced by the name of the LaTeX file during compilation.
130+
131+
Additional tags and options can also be added to edit configuration values.
132+
133+
_New in 4.2.0_: Tectonic Engine Support
134+
The extension now also supports the Tectonic engine for compiling LaTeX files. To use Tectonic as the default LaTeX engine cutomize the `jupyter_notebook_config.py file`:
135+
136+
```python
137+
c.LatexConfig.latex_command = 'tectonic'
138+
```
139+
140+
The default command sequence for Tectonic generates the output file in `pdf` format and uses the available `SyncTeX` flag.
141+
142+
For [advanced control](https://tectonic-typesetting.github.io/book/latest/v2cli/compile.html) over [Tectonic](https://github.com/tectonic-typesetting/tectonic), specify options in the manual_cmd_args setting:
143+
144+
```python
145+
c.LatexConfig.manual_cmd_args = [
146+
'tectonic',
147+
'--outfmt=pdf', # Output format as PDF
148+
'--synctex=1', # Enable SyncTeX for editor synchronization
149+
'--outdir', # The directory in which to place output files
150+
'--keep-logs', # Keep the log files generated during processing
151+
'{filename}.tex' # Input .tex file
152+
]
153+
```
154+
107155
### Security and customizing shell escapes
108156

109157
LaTeX files have the ability to run arbitrary code by triggering external

jupyterlab_latex/build.py

+46-22
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def initialize(self, root_dir):
6868
self.root_dir = root_dir
6969

7070

71-
def build_tex_cmd_sequence(self, tex_base_name, run_bibtex=False):
71+
def build_tex_cmd_sequence(self, tex_base_name):
7272
"""Builds tuples that will be used to call LaTeX shell commands.
7373
7474
Parameters
@@ -83,6 +83,8 @@ def build_tex_cmd_sequence(self, tex_base_name, run_bibtex=False):
8383
8484
"""
8585
c = LatexConfig(config=self.config)
86+
87+
engine_name = c.latex_command
8688

8789
escape_flag = ''
8890
if c.shell_escape == 'allow':
@@ -94,35 +96,57 @@ def build_tex_cmd_sequence(self, tex_base_name, run_bibtex=False):
9496

9597
# Get the synctex query parameter, defaulting to
9698
# 1 if it is not set or is invalid.
97-
synctex = self.get_query_argument('synctex', default='1')
98-
synctex = '1' if synctex != '0' else synctex
99-
100-
full_latex_sequence = (
101-
c.latex_command,
102-
escape_flag,
103-
"-interaction=nonstopmode",
104-
"-halt-on-error",
105-
"-file-line-error",
106-
f"-synctex={synctex}",
107-
f"{tex_base_name}",
99+
synctex = self.get_query_argument('synctex', default=True)
100+
101+
if c.manual_cmd_args:
102+
# Replace placeholders with actual values
103+
self.log.info("Using the manual command argument and buidling latex sequence.")
104+
full_latex_sequence = [
105+
# replace placeholders using format()
106+
arg.format(filename=tex_base_name)
107+
for arg in c.manual_cmd_args
108+
]
109+
elif engine_name == 'tectonic':
110+
self.log.info("Using Tectonic for LaTeX compilation.")
111+
full_latex_sequence = (
112+
engine_name,
113+
f"{tex_base_name}.tex", # input .tex file
114+
"--outfmt=pdf", # specify output format (pdf in this case)
115+
f"--synctex={'1' if synctex else '0'}" # to support SyncTeX (synchronization with the editor)
108116
)
109-
110-
full_bibtex_sequence = (
111-
c.bib_command,
112-
f"{tex_base_name}",
117+
else:
118+
self.log.info("Using TeX Live (or compatible distribution) for LaTeX compilation.")
119+
full_latex_sequence = (
120+
engine_name,
121+
escape_flag,
122+
"-interaction=nonstopmode",
123+
"-halt-on-error",
124+
"-file-line-error",
125+
f"-synctex={'1' if synctex else '0'}",
126+
f"{tex_base_name}",
113127
)
114-
128+
115129
command_sequence = [full_latex_sequence]
116130

117-
if run_bibtex:
131+
# Skip bibtex compilation if the following conditions are present
132+
# - c.LatexConfig.disable_bibtex is explicitly set to True
133+
# - tectonic engine is used
134+
# - there are no .bib files found in the folder
135+
if c.disable_bibtex or engine_name == 'tectonic' or not self.bib_condition():
136+
# Repeat LaTeX command run_times times
137+
command_sequence = command_sequence * c.run_times
138+
else:
139+
full_bibtex_sequence = (
140+
c.bib_command,
141+
f"{tex_base_name}",
142+
)
143+
118144
command_sequence += [
119145
full_bibtex_sequence,
120146
full_latex_sequence,
121147
full_latex_sequence,
122-
]
123-
else:
124-
command_sequence = command_sequence * c.run_times
125-
148+
]
149+
126150
return command_sequence
127151

128152
def bib_condition(self):

jupyterlab_latex/config.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
""" JupyterLab LaTex : live LaTeX editing for JupyterLab """
22

3-
from traitlets import Unicode, CaselessStrEnum, Integer, Bool
3+
from traitlets import Unicode, CaselessStrEnum, Integer, Bool, List as TraitletsList
44
from traitlets.config import Configurable
55

66
class LatexConfig(Configurable):
@@ -10,10 +10,13 @@ class LatexConfig(Configurable):
1010
"""
1111
latex_command = Unicode('xelatex', config=True,
1212
help='The LaTeX command to use when compiling ".tex" files.')
13+
disable_bibtex = Bool(default_value=False, config=True,
14+
help='Whether to disable the BibTeX command sequence.')
1315
bib_command = Unicode('bibtex', config=True,
14-
help='The BibTeX command to use when compiling ".tex" files.')
15-
synctex_command = Unicode('synctex', config=True,
16-
help='The synctex command to use when syncronizing between .tex and .pdf files.')
16+
help='The BibTeX command to use when compiling ".tex" files.' +\
17+
'Only used if disable_bibtex is not set to True')
18+
synctex_command = Bool('synctex', config=True,
19+
help='Whether to use the synctex command when syncronizing between .tex and .pdf files.')
1720
shell_escape = CaselessStrEnum(['restricted', 'allow', 'disallow'],
1821
default_value='restricted', config=True,
1922
help='Whether to allow shell escapes '+\
@@ -25,3 +28,7 @@ class LatexConfig(Configurable):
2528
help='How many times to compile the ".tex" files.')
2629
cleanup = Bool(default_value=True, config=True,
2730
help='Whether to clean up ".out/.aux" files or not.')
31+
# Add a new configuration option to hold user-defined commands
32+
manual_cmd_args = TraitletsList(Unicode(), default_value=[], config=True,
33+
help='A list of user-defined command-line arguments with placeholders for ' +
34+
'filename ({filename})')

0 commit comments

Comments
 (0)