-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompile.py
164 lines (164 loc) · 5.48 KB
/
compile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python3
#
import subprocess
import os
import time
import traceback
import gzip
import shutil
#
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
#
class ChangeHandler(PatternMatchingEventHandler):
# Only watch for changes to .tex files
patterns = ["*.tex"]
#
def process(self, event):
"""
event.event_type
'modified' | 'created' | 'moved' | 'deleted'
event.is_directory
True | False
event.src_path
path/to/observed/file
"""
#
if event.is_directory:
return
#
try:
latex_project_filename = 'latex_project.config'
compiled_path_relative_to_project_path = "compiled"
#
# First, move up the directory tree to find the project file
modified_file = event.src_path
modified_dir = os.path.dirname(modified_file)
project_directory = self.get_project_directory(modified_dir, latex_project_filename)
if project_directory is None:
print('Python script: Project file not found.')
return
#
# Using the project file, find the source file to be compiled
src_files = self.get_source_files(project_directory, latex_project_filename)
if src_files is None or len(src_files) == 0:
print('Python script: Source files not found.')
return
#
for src_file in src_files:
print('Python script: Starting file \''+src_file+'\'')
# Now the tex file can be compiled
src_file_relative_to_project_path = os.path.relpath(src_file, project_directory)
filename = os.path.splitext(os.path.basename(src_file))[0]
#
# Reasoning for commands is listed below:
# -recorder- : Since Tex Live changed the filename structure of the texlive#.lsf(?), Latexmk cannot use these files properly and gives an error. Hopefully latexmk will fix this in the future
# -synctex=-1 : We need to edit the synctex later, so don't compress it
# -interaction=nonstopmode : We don't want the script to prompt for input when errors occur
# -file-line-error : Gives more detailed error messages
commands = []
commands.append("cd \""+project_directory+"\"")
commands.append(" && mkdir -p \""+compiled_path_relative_to_project_path+"\"")
commands.append(" && latexmk -pdf -recorder- -outdir=\""+compiled_path_relative_to_project_path+"\" -aux-directory=\""+compiled_path_relative_to_project_path+"\" -pdflatex='pdflatex -synctex=-1 -interaction=nonstopmode -file-line-error' \""+src_file_relative_to_project_path+"\"")
commands.append(" | grep -A 5 '.*:[0-9]*:.*\\|!.*'")
commands.append(" > \""+compiled_path_relative_to_project_path+'/'+filename+".err\"")
#
print(''.join(commands))
subprocess.call(''.join(commands), shell=True)
#
# Finally, the synctex has to be modified to use relative paths instead of absolute paths
self.fix_synctex(project_directory, compiled_path_relative_to_project_path, filename)
#
print('Python script: Finished latexmk...')
except:
traceback.print_exc()
#
#
def on_modified(self, event):
self.process(event)
#
def on_created(self, event):
self.process(event)
#
def on_moved(self, event):
self.process(event)
#
def get_project_directory(self, startDir, projectFilename):
project_directory = startDir
#
while os.path.isdir(project_directory) and not os.path.isfile(project_directory+'/'+projectFilename):
project_directory = os.path.dirname(project_directory)
#
if project_directory == '':
# didn't find the project file
project_directory = None
#
return project_directory
#
def get_source_files(self, projectDirectory, projectFilename):
files_to_compile = []
with open(projectDirectory+'/'+projectFilename, 'r') as f:
for line in f:
line = line.strip()
if len(line) > 0 and line[0] != '#':
# if first non-whitespace character is not a '#' and line is not empty
files_to_compile.append(line)
#
#
#
for x in range(len(files_to_compile)):
if not os.path.isfile(projectDirectory+'/'+files_to_compile[x]):
print('Python script: Not a file ('+projectDirectory+'/'+files_to_compile[x]+')')
files_to_compile[x] = None
#
#
src_files = [projectDirectory+'/'+f for f in files_to_compile if f is not None]
return src_files
#
def fix_synctex(self, project_directory, compiled_path_relative_to_project_path, filename):
old_synctex = project_directory+'/'+compiled_path_relative_to_project_path+'/'+filename+'.synctex'
new_synctex = project_directory+'/'+compiled_path_relative_to_project_path+'/'+filename+'.synctex.new'
#
if os.path.isfile(old_synctex):
f1 = open(old_synctex, 'r')
f2 = open(new_synctex, 'w')
#
project_path_relative_to_compiled_path = os.path.relpath(project_directory, project_directory+'/'+compiled_path_relative_to_project_path)
for line in f1:
f2.write(line.replace(os.path.abspath(project_directory), project_path_relative_to_compiled_path))
#
f1.close()
f2.close()
os.remove(old_synctex)
#os.rename(new_synctex, old_synctex)
#
with open(new_synctex, 'rb') as f_in, gzip.open(old_synctex+'.gz', 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
#
os.remove(new_synctex)
#
#
#
if __name__ == '__main__':
handler = ChangeHandler()
directory = './'
observer = Observer()
#
if not os.path.exists(directory):
os.makedirs(directory)
#
observer.schedule(handler, directory, recursive=True)
observer.start()
#
try:
while True:
time.sleep(60*5)
# Sleep for 5 minutes (amount doesn't really matter)
#
except KeyboardInterrupt:
observer.stop()
#
observer.join()
print('')
# Add an extra new line
#