vfl 0.0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/VanillaGithub.jpg +0 -0
- data/bin/vanilla +1821 -0
- data/documentation.pdf +0 -0
- data/documentation.tex +366 -0
- data/documentation.texpack +6 -0
- data/lib/vfl.rb +5 -0
- data/lib/vfl/version.rb +3 -0
- data/src/vanilla.rb +1819 -0
- data/vfl.gemspec +23 -0
- metadata +95 -0
data/documentation.pdf
ADDED
|
Binary file
|
data/documentation.tex
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
\documentclass{article}
|
|
2
|
+
\setlength{\parindent}{0cm}
|
|
3
|
+
|
|
4
|
+
@(vfl) = **Vanilla Flavored LaTex**
|
|
5
|
+
|
|
6
|
+
@(github_url) = http://github.com/adhithyan15/vanilla
|
|
7
|
+
|
|
8
|
+
@(tmaker) = **TexMaker**
|
|
9
|
+
|
|
10
|
+
@(ftb) = formatted text blocks
|
|
11
|
+
|
|
12
|
+
@(test) = 15
|
|
13
|
+
|
|
14
|
+
@(testy) = 27
|
|
15
|
+
|
|
16
|
+
@(test1) = 17 + @(test) + @(testy)
|
|
17
|
+
|
|
18
|
+
#(cftb)[] = [$(cap)[formatted text blocks]]
|
|
19
|
+
|
|
20
|
+
$(importpack)[documentation]
|
|
21
|
+
|
|
22
|
+
\begin{document}
|
|
23
|
+
|
|
24
|
+
\begin{center}
|
|
25
|
+
|
|
26
|
+
\huge{Vanilla Documentation}\vspace{5pt}
|
|
27
|
+
|
|
28
|
+
\large{**Everything that you need to know about Vanilla**}
|
|
29
|
+
|
|
30
|
+
\end{center}
|
|
31
|
+
|
|
32
|
+
\vspace{30pt}
|
|
33
|
+
|
|
34
|
+
\section*{Copyright}
|
|
35
|
+
|
|
36
|
+
**\textcopyright Adhithya Rajasekaran, Renuka Rajasekaran, Sri Madhavi Rajasekaran**. All the contents in this document are released under a *[creative commons license => http://creativecommons.org/licenses/by-nd/3.0/].
|
|
37
|
+
|
|
38
|
+
\section*{What is Vanilla?}
|
|
39
|
+
|
|
40
|
+
Vanilla is a powerful LaTex preprocessor. It works based on the DRY(Don't Repeat Yourself) principle. It aims to reduce the entry barrier and the learning curve for Latex by simplifying the syntax and also reducing the verbosity of Latex. In this documentation you will learn how to write @(vfl) documents. This document itself is written in @(vfl) \vspace{5pt}
|
|
41
|
+
|
|
42
|
+
\section*{Why Vanilla?}
|
|
43
|
+
|
|
44
|
+
LaTex is a wonderful typesetting system but its reach is limited because of its complexity, verbose syntax and steep learning curve. So @(vfl) is directed towards solving those above mentioned problems. It derives most of its ideas from
|
|
45
|
+
**Markdown**, a small but powerful markup language.
|
|
46
|
+
|
|
47
|
+
\section*{Open Source Project}
|
|
48
|
+
|
|
49
|
+
The authors of this project have decided to open source the source code of the project. The code is hosted on *[github => https://github.com/adhithyan15/vanilla]. The code is released under MIT License. Please report any bugs to the *[issues => https://github.com/adhithyan15/vanilla/issues?state=open] tab on our github homepage. If you have any new ideas or suggestions, please leave them on the issues tab. We will greatly appreciate your feedback.
|
|
50
|
+
|
|
51
|
+
\section*{Technical Details}
|
|
52
|
+
|
|
53
|
+
Vanilla first started out as a separate markup language with a backward compatiblity to Latex. But it became apparent that there will be not enough interest in creating large amounts of libraries and productivity tools for Vanilla alone. So the authors departed from the idea and made it a preprocessor that incorporated a lot of features from their original markup language idea. \vspace{5pt}
|
|
54
|
+
|
|
55
|
+
Any LaTex document is a valid @(vfl) document but no @(vfl) document is a valid LaTex document without being processed through the Vanilla. \vspace{5pt}
|
|
56
|
+
|
|
57
|
+
The original compiler prototype was built using Matlab and then Python for more reachability. The preprocessor grew out of that compiler and was rewritten from scratch in Ruby and is shipped as a commandline utility.\vspace{5pt}
|
|
58
|
+
|
|
59
|
+
Vanilla builds on top of **PDFLatex**. So it is very important that you have any of the major tex distributions installed on your computer. If you are on windows we recommend *[MikTex => www.miktex.org] and on mac, we recommend *[MacTex => http://tug.org/mactex/]. \vspace{5pt}
|
|
60
|
+
|
|
61
|
+
\section*{Current State}
|
|
62
|
+
|
|
63
|
+
The current and stable vanilla release is version 1.0. The release provides a minimal set of base features which might be retained in most of the future releases. Significant amounts of features have been left out either due to bugs or incomplete implementation or not enough testing. They will be released in the upcoming releases. One of the main drawbacks of Vanilla is that it doesn't ship with an **error catcher and notifier**. So Vanilla will simply ignore the errors and try to compile the error free parts of the document.\vspace{5pt}
|
|
64
|
+
|
|
65
|
+
\section*{Getting Vanilla}
|
|
66
|
+
|
|
67
|
+
It is very easy to get Vanilla. Visit www.adhithyan15.github.com/vanilla/ and follow the steps below.
|
|
68
|
+
|
|
69
|
+
\begin{enumerate}
|
|
70
|
+
|
|
71
|
+
\item Click on "Download Zip" to download both the source of the compiler and also the compiled version of the compiler. \vspace{5pt}
|
|
72
|
+
|
|
73
|
+
\includegraphics[scale = 0.35]{VanillaGithub}
|
|
74
|
+
|
|
75
|
+
\item Extract the downloaded zip file using Winzip or any other archive extractor. If you don't have an archive extractor, we recommend *[ 7-zip => www.7zip.org ]
|
|
76
|
+
|
|
77
|
+
\item Once you extract it, you will find the following files inside the folder you extracted
|
|
78
|
+
|
|
79
|
+
\begin{itemize}
|
|
80
|
+
|
|
81
|
+
\item **bin**: The bin directory contains **Vanilla.exe**,**Vanilla**,and **Vanilla.rb** files. **Vanilla.exe** is the primary compiler for the windows platform and **Vanilla** is the primary compiler for the unix platform. **Vanilla.rb** file contains the ruby source code of the compiler.
|
|
82
|
+
\item **Old Compiler Prototypes**: This directory contains the prototype compilers written in Python and Matlab. Those have been open sourced just for reference purposes.
|
|
83
|
+
\item **Readme.md**: Since the project is hosted in *[ Github => @(github_url) ], Github added a readme file markuped in **Markdown**.
|
|
84
|
+
\item **VanillaGithub.jpg**: A screenshot of http://adhithyan15.github.com/vanilla page.
|
|
85
|
+
\item **Documentation.pdf**: This is the same document that you are reading right now.
|
|
86
|
+
\item **Documentation.tex**: This is the .tex version of documentation written using @(vfl). I highly recommend you to read through this document so that you can get example usages of @(vfl).
|
|
87
|
+
\item **Documentation.log**: Log file produced by **LaTex** when the file is being compiled to PDF.
|
|
88
|
+
|
|
89
|
+
\end{itemize}
|
|
90
|
+
|
|
91
|
+
\item For windows users, please follow *[this => https://github.com/adhithyan15/vanilla/wiki/Adding-Vanilla-to-Path] tutorial to add the Vanilla.exe to your path so that it can be accessed from your commandline prompt. Mac and other Unix based OS please follow *[this => https://github.com/adhithyan15/vanilla/wiki/Getting-Started-With-Vanilla-Mac-and-Unix] tutorial to add the utility to your terminal/bash.
|
|
92
|
+
|
|
93
|
+
\item You are all set. You can compile your @(vfl) documents by calling **"vanilla -~-compile somefile.tex"**. You have to set the directory in which your @(vfl) document is located as your **current directory** for the above command to work.
|
|
94
|
+
|
|
95
|
+
Please see *[this => https://github.com/adhithyan15/vanilla/wiki/Compiling-Vanilla-Flavored-LaTex-Documents] tutorial to understand what the above phrase is describing.
|
|
96
|
+
|
|
97
|
+
\end{enumerate}
|
|
98
|
+
|
|
99
|
+
Vanilla compiler can work with LaTex Editors. But configuration seems to be a problem. Vanilla is an unconventional preprocessor in which it doesn't have a seperate extension. After the preprocessing stage, Vanilla needs the authority to overwrite the original file and many of the LaTex editors block that kind of action from happening. So a solution is under development. Until such time, you can use Notepad, Notepad++, Wordpad or Sublime Text.
|
|
100
|
+
|
|
101
|
+
\section*{Features of Vanilla}
|
|
102
|
+
|
|
103
|
+
@(vfl) offers a lot of features to enhance people's productivity with LaTex. Let us see what those features below
|
|
104
|
+
|
|
105
|
+
\begin{itemize}
|
|
106
|
+
|
|
107
|
+
\item **Multiline Comments**: In @(vfl) you can comment out multiple lines of code using matlab style comments. Let us see a quick demo of this feature
|
|
108
|
+
|
|
109
|
+
###
|
|
110
|
+
|
|
111
|
+
%You can comment out multiple lines using %{.....}%
|
|
112
|
+
|
|
113
|
+
%{Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris placerat tristique purus,
|
|
114
|
+
non tempus mi ultrices in. Praesent lobortis erat et lorem commodo mollis. Pellentesque
|
|
115
|
+
eu euismod nulla.Ut vitae consequat est. Quisque adipiscing rhoncus tellus, eu fermentum
|
|
116
|
+
augue tincidunt ut. Proin a dui dignissim massa auctor iaculis dictum a purus. Suspendisse
|
|
117
|
+
porta felis at velit placerat varius.}%
|
|
118
|
+
|
|
119
|
+
###
|
|
120
|
+
|
|
121
|
+
Vanilla compiler converts @(vfl) multiline comments into several single line LaTex comments. Vanilla compiler doesn't touch the LaTex comments. So they are still valid.
|
|
122
|
+
|
|
123
|
+
\item **Constants**: Constants are very similar to variables but they are immutable. In @(vfl), you can declare constants
|
|
124
|
+
through the following sytax $@(constant\_name) = value$. Note: LaTex has offers mutable variables. We are working on implementing mutable variables in Vanilla. It will be released in
|
|
125
|
+
version 2.0.
|
|
126
|
+
|
|
127
|
+
###
|
|
128
|
+
|
|
129
|
+
@(vfl) = **Vanilla Flavored LaTex** %must be declared in the preamble
|
|
130
|
+
|
|
131
|
+
%Usage
|
|
132
|
+
|
|
133
|
+
Welcome to @(vfl) %should output Welcome to \textbf{Vanilla Flavored LaTex}
|
|
134
|
+
|
|
135
|
+
###
|
|
136
|
+
|
|
137
|
+
Constants now support what is known as a **Computed Property**. You can build new constants from other constants. An example is provided below
|
|
138
|
+
|
|
139
|
+
###
|
|
140
|
+
|
|
141
|
+
@(test) = 15
|
|
142
|
+
|
|
143
|
+
@(testy) = 27
|
|
144
|
+
|
|
145
|
+
@(test1) = 17 + @(test) + @(testy)
|
|
146
|
+
|
|
147
|
+
###
|
|
148
|
+
|
|
149
|
+
That should output @(test1). **Computed Properties** features currently doesn't support string concatenation. But it will be improved as time goes on. This addition resolves *[issue 15 => https://github.com/adhithyan15/vanilla/issues/15] on project page. Vanilla compiler doesn't compile the Vanilla constants into LaTex variables. Instead, it converts them into plain text so that they can be used in a variety of purposes.
|
|
150
|
+
Since the constants are rendered into plain text all the you can pass in a variable to most of the features listed below.
|
|
151
|
+
\item **Formatted Text Blocks**: #(cftb)[] were inspired by Less CSS' parametric mixins. #(cftb)[] can include any kind of LaTex or @(vfl) formatting.
|
|
152
|
+
@(vfl) forces the @(ftb) to be declared inside preamble to increase readability and @(ftb) are immutable. Mutable @(ftb) are under development and they will be released in version 2.0.
|
|
153
|
+
|
|
154
|
+
###
|
|
155
|
+
|
|
156
|
+
%Declaration
|
|
157
|
+
|
|
158
|
+
#(welcome_message)[@(name),@(message)] = [Welcome **@(name)**,@(message)] %should be
|
|
159
|
+
%declared in the preamble
|
|
160
|
+
|
|
161
|
+
%Usage
|
|
162
|
+
|
|
163
|
+
#(welcome_message)[Adhithya Rajasekaran,Hello World] %This should output
|
|
164
|
+
%Welcome \textbf{Adhithya Rajasekaran}, Hello World
|
|
165
|
+
|
|
166
|
+
###
|
|
167
|
+
|
|
168
|
+
#(cftb)[] can span multiple lines. Parameterless @(ftb) can be used as a constants spanning multiple lines.
|
|
169
|
+
|
|
170
|
+
###
|
|
171
|
+
|
|
172
|
+
%Declaration
|
|
173
|
+
|
|
174
|
+
#(disclaimer_statement)[] = [**WARNING**: Computer viruses can be transmitted via email.
|
|
175
|
+
The recipient should check this email and any attachments for the presence of viruses.
|
|
176
|
+
The company accepts no liability for any damage caused by any virus transmitted by this email.
|
|
177
|
+
E-mail transmission cannot be guaranteed to be secure or error-free as information could be
|
|
178
|
+
intercepted, corrupted, lost, destroyed, arrive late or incomplete, or contain viruses.
|
|
179
|
+
The sender therefore does not accept liability for any errors or omissions in the
|
|
180
|
+
contents of this message, which arise as a result of e-mail transmission.]
|
|
181
|
+
%must be declared in the preamble
|
|
182
|
+
|
|
183
|
+
%Usage
|
|
184
|
+
|
|
185
|
+
#(disclaimer_statement)[] %anywhere in the body
|
|
186
|
+
|
|
187
|
+
###
|
|
188
|
+
|
|
189
|
+
\item **Formulas**: Formulas were inspired by *[ Homebrew's => http://www.mxcl.github.com/homebrew/] formulas. @(vfl) is shipped with very few formulas
|
|
190
|
+
and the number is slowly increasing. The formulas that are shipped with @(vfl) are written for tasks that are difficult to do with LaTex. All the formulas will accept
|
|
191
|
+
accept a variable as a parameter. Let us take a look into the formulas that ship with @(vfl)
|
|
192
|
+
|
|
193
|
+
\begin{enumerate}
|
|
194
|
+
|
|
195
|
+
\item **Matrix Formula**: Matrices are very hard to construct in LaTex even with **AMSMATH** package. So @(vfl) ships with a %%\$(matrix)[]%% formula that allows
|
|
196
|
+
for the easy creation of matrices. This formula will create a matrix with square brackets around it.Let us do an example
|
|
197
|
+
|
|
198
|
+
I want to create a matrix \vspace{5pt}
|
|
199
|
+
|
|
200
|
+
A = $(matrix)[1 2 3;4 5 6;7 8 9]
|
|
201
|
+
|
|
202
|
+
###
|
|
203
|
+
|
|
204
|
+
%using AMSMATH package
|
|
205
|
+
|
|
206
|
+
A = $\begin{bmatrix} 1 & 2 & 3 \\\\ 4 & 5 & 6 \\\\ 7 & 8 & 9 \end{bmatrix}$
|
|
207
|
+
|
|
208
|
+
%using Vanilla formula $(matrix)[]
|
|
209
|
+
|
|
210
|
+
A = $(matrix)[1 2 3;4 5 6;7 8 9]
|
|
211
|
+
|
|
212
|
+
###
|
|
213
|
+
|
|
214
|
+
@(vfl) compiled the %%\$(matrix)[]%% formula into AMSMATH's **bmatrix** environment.
|
|
215
|
+
|
|
216
|
+
\item **Determinant Formula**: Determinants are very similar to matrices except they use a straight line to enclose the contents of the matrix. @(vfl) ships with
|
|
217
|
+
the %%\$(det)[]%% formula that takes care of determinants. Let us see a quick demo of this feature
|
|
218
|
+
|
|
219
|
+
I want to create a determinant \vspace{5pt}
|
|
220
|
+
|
|
221
|
+
B = $(det)[1 2 3;4 5 6;7 8 9]
|
|
222
|
+
|
|
223
|
+
###
|
|
224
|
+
|
|
225
|
+
%using AMSMATH package
|
|
226
|
+
|
|
227
|
+
B = $\begin{vmatrix} 1 & 2 & 3 \\\\ 4 & 5 & 6 \\\\ 7 & 8 & 9 \end{vmatrix}$
|
|
228
|
+
|
|
229
|
+
%using Vanilla formula $(matrix)[]
|
|
230
|
+
|
|
231
|
+
B = $(det)[1 2 3;4 5 6;7 8 9]
|
|
232
|
+
|
|
233
|
+
###
|
|
234
|
+
|
|
235
|
+
@(vfl) compiled the %%\$(det)[]%% formula into AMSMATH's **vmatrix** environment.
|
|
236
|
+
|
|
237
|
+
\item **Capitalize Formula**: Capitalize is a fun formula that capitalizes the first letter of every word in a string that is passed to it. Let us see a demo of this feature
|
|
238
|
+
|
|
239
|
+
%%\$(cap)[this is a wonderful day]%% will yield $(cap)[this is a wonderful day]
|
|
240
|
+
|
|
241
|
+
\item **Image Formula**: Image formula adds support for utilizing images from any part of the computer. By default, LaTex requires images that need to included in the PDF to be present in the same directory as the .tex file. This was believed to cause additional unnecessary work in the part of user. So the formula allows any image from any part of the computer to be used in a .tex file. The formula takes the path of the image and a ruby styled hash of options to manipulate the image. Currently **:scale**,**:width**,**:height**,**:angle** and **:page** options are supported.
|
|
242
|
+
###
|
|
243
|
+
Example Usage:
|
|
244
|
+
|
|
245
|
+
$(image)[C:\Users\Adhi\Desktop\sample.jpg,options = {:scale => 0.35}]
|
|
246
|
+
|
|
247
|
+
###
|
|
248
|
+
This resolves *[issue 10 => https://github.com/adhithyan15/vanilla/issues/10] on project page.
|
|
249
|
+
|
|
250
|
+
\end{enumerate}
|
|
251
|
+
|
|
252
|
+
As you can see that the number of formulas are very limited. Version 2.0 will allow users to create their own formulas using Ruby.
|
|
253
|
+
|
|
254
|
+
\item **Inline Calculations**: Inline calculations allow you to perform simple yet powerful calculations with in the document. You can have to nest your calculations inside ![] to perform the calculations. Let us see an example \vspace{5pt}
|
|
255
|
+
|
|
256
|
+
**%%![5*(45*(60/2))+3]%%** compiles into **![5*(45*(60/2))+3]**
|
|
257
|
+
|
|
258
|
+
\item **Inline Formatting**: Formatting is made easy by @(vfl). There are several formatting options provided by @(vfl). We will look at each one of them individually
|
|
259
|
+
|
|
260
|
+
\begin{enumerate}
|
|
261
|
+
|
|
262
|
+
\item **Boldface**: You can boldface any text using %%**some text**%% and it will output **some text**.
|
|
263
|
+
|
|
264
|
+
\item **Italicize**: You can italicize any text using %%///some text///%% and it will output ///some text///.
|
|
265
|
+
|
|
266
|
+
\item **Underline**: You can underline any text using **three underscores** on either side. Example: ___some text___ .
|
|
267
|
+
|
|
268
|
+
\item **Strikeout**: You can strikeout any text using **three tildes**. Example: ~~~2012~~~2013.
|
|
269
|
+
|
|
270
|
+
\end{enumerate}
|
|
271
|
+
|
|
272
|
+
\item **Tex Packs**: Tex Packs allow users to abstract away their most used LaTex packages into a file with any name and an extension .texpack. You can then import these Tex Packs into your @(vfl) documents by using %%\$(importpack)[package location]%% in your preamble. Tex Packs are designed to encourage reusability and seperating the structure of the document from the content of the document. The LaTex packages that this document uses have been defined in a texpack called documentation.texpack. Please take a look into that to get an idea of how to write a .texpack.
|
|
273
|
+
|
|
274
|
+
There is no special syntax for defining a texpack. You can copy and paste all the usepackage statements into a texpack and import it using the importpack function.
|
|
275
|
+
|
|
276
|
+
@(vfl) allows beginners start typesetting documents without worrying about packages. If a document doesn't have any importpack function calls or any usepackage statements, then the preprocessor will automatically add some of the most used packages to the document. The following are the packages provided out of the box by @(vfl).
|
|
277
|
+
|
|
278
|
+
\begin{enumerate}
|
|
279
|
+
|
|
280
|
+
\item Amsmath,Amssymb,Amsthm
|
|
281
|
+
|
|
282
|
+
\item Ulem with Normalem
|
|
283
|
+
|
|
284
|
+
\item Geometry with A4paper and 1.0in margin
|
|
285
|
+
|
|
286
|
+
\item Hyperref
|
|
287
|
+
|
|
288
|
+
\item Xcolor
|
|
289
|
+
|
|
290
|
+
\item Verbatim
|
|
291
|
+
|
|
292
|
+
\item Booktabs
|
|
293
|
+
|
|
294
|
+
\item Multicol
|
|
295
|
+
|
|
296
|
+
\item Graphicx
|
|
297
|
+
|
|
298
|
+
\item Siunitx
|
|
299
|
+
|
|
300
|
+
\item Cleveref
|
|
301
|
+
|
|
302
|
+
\end{enumerate}
|
|
303
|
+
|
|
304
|
+
\item **Smarty Pants Features**: These features were inspired by *[Smarty Pants => http://daringfireball.net/projects/smartypants/].
|
|
305
|
+
|
|
306
|
+
\begin{enumerate}
|
|
307
|
+
|
|
308
|
+
\item **Ellipses**: You can use %%....%% to insert ellipses anywhere. @(vfl) will be compiled to LaTex's ldots command. For example %%To be continued ....%% will become To be continuted ....
|
|
309
|
+
|
|
310
|
+
\end{enumerate}
|
|
311
|
+
|
|
312
|
+
\item **URLs and Hyperlinks**: @(vfl) provides support for two kinds of URLs out of the box. @(vfl) calls them bare urls and descriptive urls. Let us take a look into both of them.
|
|
313
|
+
|
|
314
|
+
\begin{enumerate}
|
|
315
|
+
|
|
316
|
+
\item **Bare URLs**: With @(vfl), you can just type in your URL in the document and the preprocessor will automatically find it and convert it into a LaTex hyperlink.Let us see an example
|
|
317
|
+
|
|
318
|
+
%%http://github.com/adhithyan15%% will become http://github.com/adhithyan15
|
|
319
|
+
|
|
320
|
+
\item **Descriptive URLs**: Descriptive URLs allow a word or a phrase to be hyperlinked to an URL.@(vfl) comes with a simple syntax to write descriptive URLs easily. The syntax is **%%*[word or phrase =\textgreater URL]%%**.Let us see an example
|
|
321
|
+
|
|
322
|
+
%%*[blog =\textgreater http://adhithyaraja.wordpress.com]%% will become *[blog => http://adhithyaraja.wordpress.com].
|
|
323
|
+
|
|
324
|
+
\end{enumerate}
|
|
325
|
+
|
|
326
|
+
\item **Double Quotes**: In @(vfl), you can use %%'' ''%% to surround some text with double quotes. For example, %%''hello''%% will produce "hello".
|
|
327
|
+
|
|
328
|
+
\item **Building Vanilla from Source**: You can build Vanilla executable from source using Ruby.**This only works in windows**. Make sure that you have **Ocra** gem installed. Make the bin folder the current directory. Then call "ruby vanilla.rb -b file". This will make a new windows and unix executable.
|
|
329
|
+
|
|
330
|
+
\item **Undocumented Features**: There are couple of features which were included in the compiler just for the sake of writing this documentation. They are the fenced code block and inline code block. It is not possible to demonstrate their features here because they determine whether a piece of code gets compiled by the preprocessor. You can look inside the source of this document to know how they are used.
|
|
331
|
+
|
|
332
|
+
\end{itemize}
|
|
333
|
+
|
|
334
|
+
The project is licensed under MIT License. You can read the text of the license below.
|
|
335
|
+
|
|
336
|
+
\vspace{5pt}
|
|
337
|
+
|
|
338
|
+
**License**: Copyright 2013 Adhithya Rajasekaran, Renuka Rajasekaran, Sri Madhavi Rajasekaran and other contributors
|
|
339
|
+
http://adhithyan15.github.com/vanilla
|
|
340
|
+
|
|
341
|
+
\vspace{5pt}
|
|
342
|
+
|
|
343
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
344
|
+
a copy of this software and associated documentation files (the
|
|
345
|
+
"Software"), to deal in the Software without restriction, including
|
|
346
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
347
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
348
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
349
|
+
the following conditions:
|
|
350
|
+
|
|
351
|
+
\vspace{5pt}
|
|
352
|
+
|
|
353
|
+
The above copyright notice and this permission notice shall be
|
|
354
|
+
included in all copies or substantial portions of the Software.
|
|
355
|
+
|
|
356
|
+
\vspace{5pt}
|
|
357
|
+
|
|
358
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
359
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
360
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
361
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
362
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
363
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
364
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
365
|
+
|
|
366
|
+
\end{document}
|
data/lib/vfl.rb
ADDED
data/lib/vfl/version.rb
ADDED
data/src/vanilla.rb
ADDED
|
@@ -0,0 +1,1819 @@
|
|
|
1
|
+
#Vanilla is a simple yet powerful preprocessor for LaTex
|
|
2
|
+
#
|
|
3
|
+
#The project is hosted at http://github.com/adhithyan15/vanilla
|
|
4
|
+
#
|
|
5
|
+
#This compiler is a translation of the original compiler written in Python. But a lot of algorithmic structure has been
|
|
6
|
+
#modified to give optimum performance.Some parts may be rewritten in the upcoming releases.
|
|
7
|
+
#
|
|
8
|
+
#The prototype compilers written in Matlab and Python are now available in the Old Compiler Prototypes directory
|
|
9
|
+
#
|
|
10
|
+
#Authors: Adhithya Rajasekaran and Sri Madhavi Rajasekaran
|
|
11
|
+
#
|
|
12
|
+
#To know more about the features implemented in this compiler, please read the documentation.
|
|
13
|
+
#
|
|
14
|
+
#Abbrevations: VAL => Vanilla Flavored LaTex
|
|
15
|
+
|
|
16
|
+
require 'FileUtils'
|
|
17
|
+
|
|
18
|
+
require 'optparse'
|
|
19
|
+
|
|
20
|
+
def start_compile(input_val_file) #This method starts the compilation process
|
|
21
|
+
|
|
22
|
+
def read_file_line_by_line(input_path)
|
|
23
|
+
|
|
24
|
+
#This method returns each line of the VAL file as a list
|
|
25
|
+
|
|
26
|
+
file_id = open(input_path)
|
|
27
|
+
|
|
28
|
+
file_line_by_line = file_id.readlines()
|
|
29
|
+
|
|
30
|
+
file_id.close
|
|
31
|
+
|
|
32
|
+
return file_line_by_line
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#The following are undocumented features mostly written to write the documentation.
|
|
37
|
+
|
|
38
|
+
def replace_fenced_code_block(input_file_contents,input_val_file)
|
|
39
|
+
|
|
40
|
+
#Latex offers Verbatim mode through verbatim package to prevent code from execution.Fence code block extends the verbatim mode to include
|
|
41
|
+
#VAL code also. Verbatim package is a part of our default pack so you don't have to manually import and use it.
|
|
42
|
+
|
|
43
|
+
#This method replaces all the declared fenced code blocks with @@fenced_code_block[identifier]
|
|
44
|
+
#This is done to prevent compile time error prevention.
|
|
45
|
+
|
|
46
|
+
def find_all_matching_indices(input_string,pattern)
|
|
47
|
+
|
|
48
|
+
locations = []
|
|
49
|
+
|
|
50
|
+
index = input_string.index(pattern)
|
|
51
|
+
|
|
52
|
+
while index != nil
|
|
53
|
+
|
|
54
|
+
locations << index
|
|
55
|
+
|
|
56
|
+
index = input_string.index(pattern,index+1)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
return locations
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def find_val_file_path(input_path)
|
|
67
|
+
|
|
68
|
+
#This method is utilized to extract the path of the VAL file.
|
|
69
|
+
|
|
70
|
+
extension_remover = input_path.split(".tex")
|
|
71
|
+
|
|
72
|
+
remaining_string = extension_remover[0].reverse
|
|
73
|
+
|
|
74
|
+
path_finder = remaining_string.index("/")
|
|
75
|
+
|
|
76
|
+
remaining_string = remaining_string.reverse
|
|
77
|
+
|
|
78
|
+
return remaining_string[0...remaining_string.length-path_finder]
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
input_file_as_string = input_file_contents.join
|
|
83
|
+
|
|
84
|
+
modified_input_string = input_file_as_string.dup
|
|
85
|
+
|
|
86
|
+
preferred_directory = find_val_file_path(input_val_file)
|
|
87
|
+
|
|
88
|
+
locate_fenced_code_block = find_all_matching_indices(input_file_as_string,"###")
|
|
89
|
+
|
|
90
|
+
fenced_code_block = []
|
|
91
|
+
|
|
92
|
+
start_location = 0
|
|
93
|
+
|
|
94
|
+
end_location = 1
|
|
95
|
+
|
|
96
|
+
if locate_fenced_code_block.length.modulo(2) == 0
|
|
97
|
+
|
|
98
|
+
for x in 0...locate_fenced_code_block.length/2
|
|
99
|
+
|
|
100
|
+
fenced_code_block_string = input_file_as_string[locate_fenced_code_block[start_location]..locate_fenced_code_block[end_location]+2]
|
|
101
|
+
|
|
102
|
+
fenced_code_block << fenced_code_block_string
|
|
103
|
+
|
|
104
|
+
replacement_string = "@@fenced_code_block[#{x+1}]"
|
|
105
|
+
|
|
106
|
+
modified_input_string = modified_input_string.sub(fenced_code_block_string,replacement_string)
|
|
107
|
+
|
|
108
|
+
start_location = start_location + 2
|
|
109
|
+
|
|
110
|
+
end_location = end_location + 2
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
temporary_file_path = find_val_file_path(input_val_file) + "temp.tex"
|
|
117
|
+
|
|
118
|
+
file_id = open(temporary_file_path, 'w')
|
|
119
|
+
|
|
120
|
+
file_id.write(modified_input_string)
|
|
121
|
+
|
|
122
|
+
file_id.close()
|
|
123
|
+
|
|
124
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
125
|
+
|
|
126
|
+
return line_by_line_contents, temporary_file_path, fenced_code_block,preferred_directory
|
|
127
|
+
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def replace_inline_fenced_code(input_file_contents,temporary_file_path)
|
|
131
|
+
|
|
132
|
+
#This method will prevent inline VAL code from being compiled. This will only prevent VAL code from being
|
|
133
|
+
#compiled. If the inline code contains LaTex code, then LaTex compiler will compile it into PDF.
|
|
134
|
+
#This method was mainly written for presenting VAL code in the Vanilla documentation.
|
|
135
|
+
|
|
136
|
+
#This uses the same methodology as the fenced code block. Tt replaces inline code blocks with
|
|
137
|
+
#@@inline_code_bloc[identifier]
|
|
138
|
+
|
|
139
|
+
def find_all_matching_indices(input_string,pattern)
|
|
140
|
+
|
|
141
|
+
locations = []
|
|
142
|
+
|
|
143
|
+
index = input_string.index(pattern)
|
|
144
|
+
|
|
145
|
+
while index != nil
|
|
146
|
+
|
|
147
|
+
locations << index
|
|
148
|
+
|
|
149
|
+
index = input_string.index(pattern,index+1)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
return locations
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
input_file_as_string = input_file_contents.join
|
|
160
|
+
|
|
161
|
+
modified_input_string = input_file_as_string.dup
|
|
162
|
+
|
|
163
|
+
locate_inline_code_block = find_all_matching_indices(input_file_as_string,"%%")
|
|
164
|
+
|
|
165
|
+
inline_code_block = []
|
|
166
|
+
|
|
167
|
+
start_location = 0
|
|
168
|
+
|
|
169
|
+
end_location = 1
|
|
170
|
+
|
|
171
|
+
if locate_inline_code_block.length.modulo(2) == 0
|
|
172
|
+
|
|
173
|
+
for x in 0...locate_inline_code_block.length/2
|
|
174
|
+
|
|
175
|
+
inline_code_block_string = input_file_as_string[locate_inline_code_block[start_location]..locate_inline_code_block[end_location]+1]
|
|
176
|
+
|
|
177
|
+
inline_code_block << inline_code_block_string
|
|
178
|
+
|
|
179
|
+
replacement_string = "@@inline_code_block[#{x+1}]"
|
|
180
|
+
|
|
181
|
+
modified_input_string = modified_input_string.sub(inline_code_block_string,replacement_string)
|
|
182
|
+
|
|
183
|
+
start_location = start_location + 2
|
|
184
|
+
|
|
185
|
+
end_location = end_location + 2
|
|
186
|
+
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
file_id = open(temporary_file_path, 'w')
|
|
192
|
+
|
|
193
|
+
file_id.write(modified_input_string)
|
|
194
|
+
|
|
195
|
+
file_id.close()
|
|
196
|
+
|
|
197
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
198
|
+
|
|
199
|
+
return line_by_line_contents, temporary_file_path, inline_code_block
|
|
200
|
+
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
#The following features are documented features.
|
|
204
|
+
|
|
205
|
+
def resolve_comments(input_file_contents,temporary_file_path)
|
|
206
|
+
|
|
207
|
+
#Latex does offer support for multiline comments. But VAL makes the process easier. This method compiles
|
|
208
|
+
#VAL multiline comments into several single line latex comments.Latex comments are still valid in VAL.
|
|
209
|
+
|
|
210
|
+
def find_all_matching_indices(input_string,pattern)
|
|
211
|
+
|
|
212
|
+
locations = []
|
|
213
|
+
|
|
214
|
+
index = input_string.index(pattern)
|
|
215
|
+
|
|
216
|
+
while index != nil
|
|
217
|
+
|
|
218
|
+
locations << index
|
|
219
|
+
|
|
220
|
+
index = input_string.index(pattern,index+1)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
return locations
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
input_file_as_string = input_file_contents.join
|
|
231
|
+
|
|
232
|
+
modified_input_string = input_file_as_string.dup
|
|
233
|
+
|
|
234
|
+
location_of_multiline_comments_start = find_all_matching_indices(input_file_as_string,"%{")
|
|
235
|
+
|
|
236
|
+
location_of_multiline_comments_end = find_all_matching_indices(input_file_as_string,"}%")
|
|
237
|
+
|
|
238
|
+
if location_of_multiline_comments_start.length == location_of_multiline_comments_end.length
|
|
239
|
+
|
|
240
|
+
for x in 0...location_of_multiline_comments_start.length
|
|
241
|
+
|
|
242
|
+
multiline_comment = input_file_as_string[location_of_multiline_comments_start[x]..location_of_multiline_comments_end[x]+1]
|
|
243
|
+
|
|
244
|
+
replacement_comment = multiline_comment.sub("%{","")
|
|
245
|
+
|
|
246
|
+
replacement_comment = replacement_comment.sub("}%","")
|
|
247
|
+
|
|
248
|
+
multiline_comment_split = replacement_comment.split("\n")
|
|
249
|
+
|
|
250
|
+
for y in 0...multiline_comment_split.length
|
|
251
|
+
|
|
252
|
+
multiline_comment_split[y] = "%" + multiline_comment_split[y]
|
|
253
|
+
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
replacement_comment = multiline_comment_split.join("\n")
|
|
257
|
+
|
|
258
|
+
modified_input_string = modified_input_string.sub(multiline_comment,replacement_comment)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
file_id = open(temporary_file_path, 'w')
|
|
266
|
+
|
|
267
|
+
file_id.write(modified_input_string)
|
|
268
|
+
|
|
269
|
+
file_id.close()
|
|
270
|
+
|
|
271
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
272
|
+
|
|
273
|
+
return line_by_line_contents, temporary_file_path
|
|
274
|
+
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def resolve_constants(input_file_contents, temporary_file_path)
|
|
278
|
+
|
|
279
|
+
#Latex does offer support for declaring constants. But VAL greatly simplifies the process of declaring those constants.
|
|
280
|
+
#You can still use latex constants.
|
|
281
|
+
|
|
282
|
+
#Note:VAL constants are not transformed into Latex constants. Constants stand for what they mean.They are immutable.
|
|
283
|
+
#Pure mutable variables may be available in VAL in the future. Lexical Scoping of constants is similar to that in
|
|
284
|
+
#programming languages. This would be imminent in the code block resolution method.
|
|
285
|
+
|
|
286
|
+
#Updates 2/16/2012 -> Constants now support what our user called "Computed Properties". So users can now include
|
|
287
|
+
#calculations and reference other constants while declaring constants.
|
|
288
|
+
|
|
289
|
+
def retrieve_constants(input_file_contents)
|
|
290
|
+
|
|
291
|
+
#This method looks into the preamble of the document and picks up all the constant declarations. Then it splits and
|
|
292
|
+
#produces an array of constant names and constant values.
|
|
293
|
+
|
|
294
|
+
end_of_preamble = 0
|
|
295
|
+
|
|
296
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
297
|
+
|
|
298
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
299
|
+
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
preamble = input_file_contents[0...end_of_preamble]
|
|
303
|
+
|
|
304
|
+
modified_preamble = preamble.dup
|
|
305
|
+
|
|
306
|
+
length_of_preamble = preamble.length
|
|
307
|
+
|
|
308
|
+
variable_list = []
|
|
309
|
+
|
|
310
|
+
for x in 0...length_of_preamble
|
|
311
|
+
|
|
312
|
+
current_row = preamble[x]
|
|
313
|
+
|
|
314
|
+
if !current_row.include?("%")
|
|
315
|
+
|
|
316
|
+
if !current_row.include?("#")
|
|
317
|
+
|
|
318
|
+
if current_row.include?("@")
|
|
319
|
+
|
|
320
|
+
if current_row.index("@") == 0
|
|
321
|
+
|
|
322
|
+
if current_row.split("=").length() == 2
|
|
323
|
+
|
|
324
|
+
modified_preamble.delete(current_row)
|
|
325
|
+
|
|
326
|
+
variable_list << current_row.strip
|
|
327
|
+
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
else
|
|
337
|
+
|
|
338
|
+
inline_comment_finder = current_row.index("%")
|
|
339
|
+
|
|
340
|
+
operating_string = current_row[0...inline_comment_finder]
|
|
341
|
+
|
|
342
|
+
if !operating_string.include?("#")
|
|
343
|
+
|
|
344
|
+
if operating_string.include?("@")
|
|
345
|
+
|
|
346
|
+
if operating_string.index("@") == 0
|
|
347
|
+
|
|
348
|
+
if operating_string.split("=").length() == 2
|
|
349
|
+
|
|
350
|
+
modified_preamble.delete(current_row)
|
|
351
|
+
|
|
352
|
+
variable_list << operating_string.strip
|
|
353
|
+
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
variable_names = []
|
|
367
|
+
|
|
368
|
+
variable_values = []
|
|
369
|
+
|
|
370
|
+
for y in 0...variable_list.length
|
|
371
|
+
|
|
372
|
+
current_row = variable_list[y]
|
|
373
|
+
|
|
374
|
+
variable_name_and_value = current_row.split("=")
|
|
375
|
+
|
|
376
|
+
variable_names << variable_name_and_value[0].strip
|
|
377
|
+
|
|
378
|
+
variable_values << variable_name_and_value[1].strip
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
modified_variable_values = []
|
|
384
|
+
|
|
385
|
+
variable_values.each do |value|
|
|
386
|
+
|
|
387
|
+
if value.include? "@("
|
|
388
|
+
|
|
389
|
+
new_value = value.dup
|
|
390
|
+
|
|
391
|
+
variable_names.each do |name|
|
|
392
|
+
|
|
393
|
+
if new_value.include? name
|
|
394
|
+
|
|
395
|
+
new_value = new_value.sub(name,variable_values[variable_names.index(name)])
|
|
396
|
+
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
ruby_binding = binding
|
|
402
|
+
|
|
403
|
+
val = ruby_binding.eval(new_value).to_s
|
|
404
|
+
|
|
405
|
+
modified_variable_values << val
|
|
406
|
+
|
|
407
|
+
else
|
|
408
|
+
|
|
409
|
+
modified_variable_values << value
|
|
410
|
+
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
return variable_names, modified_variable_values, modified_preamble
|
|
416
|
+
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
variable_names, variable_values, preamble = retrieve_constants(input_file_contents)
|
|
420
|
+
|
|
421
|
+
end_of_preamble = 0
|
|
422
|
+
|
|
423
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
424
|
+
|
|
425
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
426
|
+
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
document_body = input_file_contents[end_of_preamble..-1].join
|
|
430
|
+
|
|
431
|
+
for x in 0...variable_names.length
|
|
432
|
+
|
|
433
|
+
current_variable = variable_names[x]
|
|
434
|
+
|
|
435
|
+
document_body = document_body.gsub(current_variable, variable_values[x])
|
|
436
|
+
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
file_id = open(temporary_file_path, 'w')
|
|
440
|
+
|
|
441
|
+
file_id.write(preamble.join+document_body)
|
|
442
|
+
|
|
443
|
+
file_id.close()
|
|
444
|
+
|
|
445
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
446
|
+
|
|
447
|
+
return line_by_line_contents, temporary_file_path
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def resolve_formatted_text_blocks(input_file_contents,temporary_file_path)
|
|
453
|
+
|
|
454
|
+
#This method will resolve formatted text blocks. The idea of formatted code blocks was inspired by Lesscss' parametric mixins.
|
|
455
|
+
|
|
456
|
+
#Latex doesn't offer support for formatted text blocks. So VAL provides support for it.
|
|
457
|
+
|
|
458
|
+
def retrieve_formatted_text_blocks(input_file_contents)
|
|
459
|
+
|
|
460
|
+
#This method will go through the preamble and will retrieve a list of declared formatted text blocks
|
|
461
|
+
|
|
462
|
+
def remove_comments(input_string)
|
|
463
|
+
|
|
464
|
+
#This method will remove comments from a string.This method is part of a large rewrite operation to reduce the clutter
|
|
465
|
+
#in the code and also to increase performance
|
|
466
|
+
|
|
467
|
+
if input_string.include?("%")
|
|
468
|
+
|
|
469
|
+
output_string = input_string[0...input_string.index("%")]
|
|
470
|
+
|
|
471
|
+
else
|
|
472
|
+
|
|
473
|
+
output_string = input_string
|
|
474
|
+
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
return output_string
|
|
478
|
+
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
end_of_preamble = 0
|
|
482
|
+
|
|
483
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
484
|
+
|
|
485
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
486
|
+
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
preamble = input_file_contents[0...end_of_preamble]
|
|
490
|
+
|
|
491
|
+
modified_preamble = preamble.dup
|
|
492
|
+
|
|
493
|
+
length_of_preamble = preamble.length
|
|
494
|
+
|
|
495
|
+
text_blocks_list = []
|
|
496
|
+
|
|
497
|
+
for x in 0...preamble.length
|
|
498
|
+
|
|
499
|
+
current_row = preamble[x]
|
|
500
|
+
|
|
501
|
+
if current_row.include?("#")
|
|
502
|
+
|
|
503
|
+
if current_row.include?("%")
|
|
504
|
+
|
|
505
|
+
operating_string = current_row[0...current_row.index("%")]
|
|
506
|
+
|
|
507
|
+
comment_string = current_row[current_row.index("%")..-1]
|
|
508
|
+
|
|
509
|
+
else
|
|
510
|
+
|
|
511
|
+
operating_string = current_row
|
|
512
|
+
|
|
513
|
+
comment_string = ""
|
|
514
|
+
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
text_block_finder = operating_string.split("=")
|
|
518
|
+
|
|
519
|
+
if text_block_finder.length > 1
|
|
520
|
+
|
|
521
|
+
if text_block_finder[1].include?("[")
|
|
522
|
+
|
|
523
|
+
if text_block_finder[1].include?("]")
|
|
524
|
+
|
|
525
|
+
code_block = [operating_string]
|
|
526
|
+
|
|
527
|
+
modified_preamble.delete(operating_string+comment_string)
|
|
528
|
+
|
|
529
|
+
text_blocks_list << code_block.join("")
|
|
530
|
+
|
|
531
|
+
else
|
|
532
|
+
|
|
533
|
+
next_index = x
|
|
534
|
+
|
|
535
|
+
code_block = []
|
|
536
|
+
|
|
537
|
+
text_block_end_finder = text_block_finder[1].include?("]")
|
|
538
|
+
|
|
539
|
+
while text_block_end_finder == false
|
|
540
|
+
|
|
541
|
+
code_block << preamble[next_index]
|
|
542
|
+
|
|
543
|
+
modified_preamble.delete(preamble[next_index])
|
|
544
|
+
|
|
545
|
+
next_index = next_index + 1
|
|
546
|
+
|
|
547
|
+
text_block_end_finder = preamble[next_index].include?("]")
|
|
548
|
+
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
code_block << remove_comments(preamble[next_index])
|
|
552
|
+
|
|
553
|
+
modified_preamble.delete(preamble[next_index])
|
|
554
|
+
|
|
555
|
+
text_blocks_list << code_block.join("")
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
code_block_names = []
|
|
569
|
+
|
|
570
|
+
code_block_values = []
|
|
571
|
+
|
|
572
|
+
for x in 0...text_blocks_list.length
|
|
573
|
+
|
|
574
|
+
current_text_block = text_blocks_list[x]
|
|
575
|
+
|
|
576
|
+
text_block_name_and_value = current_text_block.split("=")
|
|
577
|
+
|
|
578
|
+
code_block_names << text_block_name_and_value[0].strip
|
|
579
|
+
|
|
580
|
+
code_block_values << text_block_name_and_value[1].strip
|
|
581
|
+
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
return code_block_names,code_block_values,modified_preamble
|
|
585
|
+
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def extract_parameters(names_with_params)
|
|
589
|
+
|
|
590
|
+
code_block_names = []
|
|
591
|
+
|
|
592
|
+
code_block_params = []
|
|
593
|
+
|
|
594
|
+
for x in 0...names_with_params.length
|
|
595
|
+
|
|
596
|
+
current_code_block_name = names_with_params[x]
|
|
597
|
+
|
|
598
|
+
params_split = current_code_block_name.split("[")
|
|
599
|
+
|
|
600
|
+
code_block_names << params_split[0]
|
|
601
|
+
|
|
602
|
+
params_list = params_split[1]
|
|
603
|
+
|
|
604
|
+
params_list = params_list[0...-1]
|
|
605
|
+
|
|
606
|
+
code_block_params << params_list
|
|
607
|
+
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
return code_block_names,code_block_params
|
|
611
|
+
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def find_all_matching_indices(input_string,pattern)
|
|
615
|
+
|
|
616
|
+
locations = []
|
|
617
|
+
|
|
618
|
+
index = input_string.index(pattern)
|
|
619
|
+
|
|
620
|
+
while index != nil
|
|
621
|
+
|
|
622
|
+
locations << index
|
|
623
|
+
|
|
624
|
+
index = input_string.index(pattern,index+1)
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
return locations
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
block_names_params,code_block_values,preamble = retrieve_formatted_text_blocks(input_file_contents)
|
|
635
|
+
|
|
636
|
+
code_block_names,code_block_params = extract_parameters(block_names_params)
|
|
637
|
+
|
|
638
|
+
end_of_preamble = 0
|
|
639
|
+
|
|
640
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
641
|
+
|
|
642
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
643
|
+
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
document_body = input_file_contents[end_of_preamble..-1]
|
|
647
|
+
|
|
648
|
+
document_body_as_string = document_body.join("")
|
|
649
|
+
|
|
650
|
+
modified_document_as_string = document_body_as_string.dup
|
|
651
|
+
|
|
652
|
+
for x in 0...code_block_names.length
|
|
653
|
+
|
|
654
|
+
current_code_block_name = code_block_names[x]
|
|
655
|
+
|
|
656
|
+
current_code_block_params = code_block_params[x]
|
|
657
|
+
|
|
658
|
+
current_code_block_params = current_code_block_params.split(",")
|
|
659
|
+
|
|
660
|
+
current_code_block_value = code_block_values[x]
|
|
661
|
+
|
|
662
|
+
current_code_block_value = current_code_block_value[1...-1]
|
|
663
|
+
|
|
664
|
+
location_of_code_block = find_all_matching_indices(document_body_as_string,current_code_block_name)
|
|
665
|
+
|
|
666
|
+
for y in 0...location_of_code_block.length
|
|
667
|
+
|
|
668
|
+
code_block_end_finder = document_body_as_string.index("]",location_of_code_block[y])
|
|
669
|
+
|
|
670
|
+
text_block_string = document_body_as_string[location_of_code_block[y]..code_block_end_finder]
|
|
671
|
+
|
|
672
|
+
param_split = text_block_string.split("[")
|
|
673
|
+
|
|
674
|
+
text_block_params = param_split[1]
|
|
675
|
+
|
|
676
|
+
text_block_params = text_block_params[0...-1]
|
|
677
|
+
|
|
678
|
+
text_block_params = text_block_params.split(",")
|
|
679
|
+
|
|
680
|
+
if text_block_params.length == current_code_block_params.length
|
|
681
|
+
|
|
682
|
+
parameter_map = Hash[*current_code_block_params.zip(text_block_params).flatten]
|
|
683
|
+
|
|
684
|
+
replacement_string = current_code_block_value
|
|
685
|
+
|
|
686
|
+
for z in 0...parameter_map.length
|
|
687
|
+
|
|
688
|
+
replacement_string = replacement_string.gsub(current_code_block_params[z],parameter_map[current_code_block_params[z]])
|
|
689
|
+
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
modified_document_as_string = modified_document_as_string.sub(text_block_string,replacement_string)
|
|
693
|
+
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
file_id = open(temporary_file_path, 'w')
|
|
701
|
+
|
|
702
|
+
file_id.write(preamble.join+modified_document_as_string)
|
|
703
|
+
|
|
704
|
+
file_id.close()
|
|
705
|
+
|
|
706
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
707
|
+
|
|
708
|
+
return line_by_line_contents, temporary_file_path
|
|
709
|
+
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
def resolve_formulas(input_file_contents,temporary_file_path)
|
|
713
|
+
|
|
714
|
+
#VAL Formulas are easy way to achieve certain things which are very difficult to achieve in Latex. Writing matrices
|
|
715
|
+
#is very difficult in latex. As time progresses, more formulas will be added to simplify latex typesetting.
|
|
716
|
+
|
|
717
|
+
def find_all_matching_indices(input_string,pattern)
|
|
718
|
+
|
|
719
|
+
locations = []
|
|
720
|
+
|
|
721
|
+
index = input_string.index(pattern)
|
|
722
|
+
|
|
723
|
+
while index != nil
|
|
724
|
+
|
|
725
|
+
locations << index
|
|
726
|
+
|
|
727
|
+
index = input_string.index(pattern,index+1)
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
return locations
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
def convert_to_matrix(input_list)
|
|
738
|
+
|
|
739
|
+
#This method converts the input list to latex's bmatrix environment offered through amsmath package.
|
|
740
|
+
|
|
741
|
+
start_string = "$\\begin{bmatrix}"
|
|
742
|
+
|
|
743
|
+
end_string = "\\end{bmatrix}$"
|
|
744
|
+
|
|
745
|
+
rows = []
|
|
746
|
+
|
|
747
|
+
for x in 0...input_list.length
|
|
748
|
+
|
|
749
|
+
current_row = input_list[x]
|
|
750
|
+
|
|
751
|
+
current_row_string = current_row.split.join(" & ")
|
|
752
|
+
|
|
753
|
+
rows << current_row_string
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
matrix = rows.join(" \\\\\\\\\\\\\\\\ ")
|
|
759
|
+
|
|
760
|
+
matrix = "$" + start_string + matrix + end_string + "$"
|
|
761
|
+
|
|
762
|
+
return matrix
|
|
763
|
+
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
def convert_to_determinant(input_list)
|
|
767
|
+
|
|
768
|
+
#This method converts the input list to latex's vmatrix environment offered through amsmath package.
|
|
769
|
+
|
|
770
|
+
start_string = "\\begin{vmatrix}"
|
|
771
|
+
|
|
772
|
+
end_string = "\\end{vmatrix}"
|
|
773
|
+
|
|
774
|
+
rows = []
|
|
775
|
+
|
|
776
|
+
for x in 0...input_list.length
|
|
777
|
+
|
|
778
|
+
current_row = input_list[x]
|
|
779
|
+
|
|
780
|
+
current_row_string = current_row.split.join(" & ")
|
|
781
|
+
|
|
782
|
+
rows << current_row_string
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
determinant = rows.join(" \\\\\\\\\\\\\\\\ ")
|
|
788
|
+
|
|
789
|
+
determinant = "$" + start_string + determinant + end_string + "$"
|
|
790
|
+
|
|
791
|
+
return determinant
|
|
792
|
+
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
def capitalize(input_string)
|
|
796
|
+
|
|
797
|
+
#This method will capitalize every single word in a string
|
|
798
|
+
|
|
799
|
+
input_string_split = input_string.split
|
|
800
|
+
|
|
801
|
+
for x in 0...input_string_split.length
|
|
802
|
+
|
|
803
|
+
current_word = input_string_split[x]
|
|
804
|
+
|
|
805
|
+
if current_word.length > 1
|
|
806
|
+
|
|
807
|
+
current_word = current_word[0].upcase + current_word[1..-1]
|
|
808
|
+
|
|
809
|
+
else
|
|
810
|
+
|
|
811
|
+
current_word = current_word.upcase
|
|
812
|
+
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
input_string_split[x] = current_word
|
|
816
|
+
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
return input_string_split.join(" ")
|
|
820
|
+
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
def image(input_string_split,temp_file_path)
|
|
824
|
+
|
|
825
|
+
def find_file_path(input_path,file_extension)
|
|
826
|
+
|
|
827
|
+
extension_remover = input_path.split(file_extension)
|
|
828
|
+
|
|
829
|
+
remaining_string = extension_remover[0].reverse
|
|
830
|
+
|
|
831
|
+
if remaining_string.include?("\\")
|
|
832
|
+
|
|
833
|
+
path_finder = remaining_string.index("\\")
|
|
834
|
+
|
|
835
|
+
elsif remaining_string.include?("/")
|
|
836
|
+
|
|
837
|
+
path_finder = remaining_string.index("/")
|
|
838
|
+
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
remaining_string = remaining_string.reverse
|
|
842
|
+
|
|
843
|
+
return remaining_string[0...remaining_string.length-path_finder]
|
|
844
|
+
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
def find_file_name(input_path,file_extension)
|
|
848
|
+
|
|
849
|
+
extension_remover = input_path.split(file_extension)
|
|
850
|
+
|
|
851
|
+
remaining_string = extension_remover[0].reverse
|
|
852
|
+
|
|
853
|
+
path_finder = remaining_string.index("\\")
|
|
854
|
+
|
|
855
|
+
remaining_string = remaining_string.reverse
|
|
856
|
+
|
|
857
|
+
return remaining_string[remaining_string.length-path_finder..-1]
|
|
858
|
+
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
def find_file_extension(input_path)
|
|
862
|
+
|
|
863
|
+
extension_start = input_path.index(".")
|
|
864
|
+
|
|
865
|
+
return input_path[extension_start..-1]
|
|
866
|
+
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
available_options = ["scale","width","height","angle","page"]
|
|
870
|
+
|
|
871
|
+
image_path = input_string_split[0]
|
|
872
|
+
|
|
873
|
+
options = input_string_split[1]
|
|
874
|
+
|
|
875
|
+
current_destination = find_file_path(image_path,find_file_extension(image_path))
|
|
876
|
+
|
|
877
|
+
to_be_moved_destination = find_file_path(temp_file_path,".tex")
|
|
878
|
+
|
|
879
|
+
to_be_moved_dest = to_be_moved_destination + "/#{find_file_name(image_path,"#{find_file_extension(image_path)}")}#{find_file_extension(image_path)}"
|
|
880
|
+
|
|
881
|
+
if !current_destination.eql? to_be_moved_destination
|
|
882
|
+
|
|
883
|
+
FileUtils.cp image_path,to_be_moved_dest
|
|
884
|
+
|
|
885
|
+
eval_binding = binding
|
|
886
|
+
|
|
887
|
+
options_hash = eval_binding.eval(options)
|
|
888
|
+
|
|
889
|
+
option_values = []
|
|
890
|
+
|
|
891
|
+
available_options.each do |option|
|
|
892
|
+
|
|
893
|
+
if options_hash.has_key?(option.to_sym)
|
|
894
|
+
|
|
895
|
+
option_values << option + " = #{options_hash[option.to_sym]}"
|
|
896
|
+
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
return_string = "\\\\includegraphics[#{option_values.join(",")}]{#{find_file_name(image_path,"#{find_file_extension(image_path)}")}}"
|
|
902
|
+
|
|
903
|
+
else
|
|
904
|
+
|
|
905
|
+
eval_binding = binding
|
|
906
|
+
|
|
907
|
+
options_hash = eval_binding.eval(options)
|
|
908
|
+
|
|
909
|
+
option_values = []
|
|
910
|
+
|
|
911
|
+
available_options.each do |option|
|
|
912
|
+
|
|
913
|
+
option_values << option + " = #{options_hash[option.to_sym]}"
|
|
914
|
+
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
return_string = "\\\\includegraphics[#{option_values.join(",")}]{#{find_file_name(image_path,".#{find_file_extension(image_path)}")}}"
|
|
918
|
+
|
|
919
|
+
end
|
|
920
|
+
|
|
921
|
+
return return_string
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
available_formulas = ["$(matrix)","$(det)","$(cap)","$(image)"]
|
|
927
|
+
|
|
928
|
+
input_file_as_string = input_file_contents.join
|
|
929
|
+
|
|
930
|
+
modified_input_string = input_file_as_string.dup
|
|
931
|
+
|
|
932
|
+
for x in 0...available_formulas.length
|
|
933
|
+
|
|
934
|
+
current_formula = available_formulas[x]
|
|
935
|
+
|
|
936
|
+
location_of_current_formula = find_all_matching_indices(input_file_as_string,current_formula)
|
|
937
|
+
|
|
938
|
+
for y in 0...location_of_current_formula.length
|
|
939
|
+
|
|
940
|
+
replacement_string = ""
|
|
941
|
+
|
|
942
|
+
extract_string = input_file_as_string[location_of_current_formula[y]..-1]
|
|
943
|
+
|
|
944
|
+
current_formula_end = extract_string.index("]")
|
|
945
|
+
|
|
946
|
+
formula_usage_string = extract_string[0..current_formula_end]
|
|
947
|
+
|
|
948
|
+
formula_usage_string_split = formula_usage_string.split("[")
|
|
949
|
+
|
|
950
|
+
formula_usage_string_split = formula_usage_string_split[1].split("]")
|
|
951
|
+
|
|
952
|
+
if x == 0
|
|
953
|
+
|
|
954
|
+
formula_usage_string_split = formula_usage_string_split[0].split(";")
|
|
955
|
+
|
|
956
|
+
replacement_string = convert_to_matrix(formula_usage_string_split)
|
|
957
|
+
|
|
958
|
+
elsif x == 1
|
|
959
|
+
|
|
960
|
+
formula_usage_string_split = formula_usage_string_split[0].split(";")
|
|
961
|
+
|
|
962
|
+
replacement_string = convert_to_determinant(formula_usage_string_split)
|
|
963
|
+
|
|
964
|
+
elsif x == 2
|
|
965
|
+
|
|
966
|
+
replacement_string = capitalize(formula_usage_string_split[0])
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
elsif x == 3
|
|
970
|
+
|
|
971
|
+
replacement_string = image(formula_usage_string_split[0].split(","),temporary_file_path)
|
|
972
|
+
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
modified_input_string = modified_input_string.sub(formula_usage_string,replacement_string)
|
|
976
|
+
|
|
977
|
+
end
|
|
978
|
+
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
file_id = open(temporary_file_path, 'w')
|
|
982
|
+
|
|
983
|
+
file_id.write(modified_input_string)
|
|
984
|
+
|
|
985
|
+
file_id.close()
|
|
986
|
+
|
|
987
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
988
|
+
|
|
989
|
+
return line_by_line_contents, temporary_file_path
|
|
990
|
+
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
def resolve_inline_calculations(input_file_contents,temporary_file_path)
|
|
994
|
+
|
|
995
|
+
#This method is used in converting inline calculations into answers. It uses ruby's eval method to achieve this.
|
|
996
|
+
|
|
997
|
+
def find_all_matching_indices(input_string,pattern)
|
|
998
|
+
|
|
999
|
+
locations = []
|
|
1000
|
+
|
|
1001
|
+
index = input_string.index(pattern)
|
|
1002
|
+
|
|
1003
|
+
while index != nil
|
|
1004
|
+
|
|
1005
|
+
locations << index
|
|
1006
|
+
|
|
1007
|
+
index = input_string.index(pattern,index+1)
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
return locations
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
end
|
|
1016
|
+
|
|
1017
|
+
for x in 0...input_file_contents.length
|
|
1018
|
+
|
|
1019
|
+
current_row = input_file_contents[x]
|
|
1020
|
+
|
|
1021
|
+
operating_row = current_row.dup
|
|
1022
|
+
|
|
1023
|
+
comment_string = ""
|
|
1024
|
+
|
|
1025
|
+
if current_row.include?("%")
|
|
1026
|
+
|
|
1027
|
+
operating_row = current_row[0...current_row.index("%")]
|
|
1028
|
+
|
|
1029
|
+
comment_string = current_row[current_row.index("%")...-1]
|
|
1030
|
+
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
inline_calculation_strings = operating_row.match /!\[.{1,}\]/
|
|
1034
|
+
|
|
1035
|
+
inline_calculation_strings = inline_calculation_strings.to_a
|
|
1036
|
+
|
|
1037
|
+
for y in 0...inline_calculation_strings.length
|
|
1038
|
+
|
|
1039
|
+
inline_calculation_string = inline_calculation_strings[y]
|
|
1040
|
+
|
|
1041
|
+
inline_calc_ruby_string = inline_calculation_string.dup
|
|
1042
|
+
|
|
1043
|
+
inline_calc_ruby_string = inline_calc_ruby_string[2...-1]
|
|
1044
|
+
|
|
1045
|
+
inline_calc_ruby_string = inline_calc_ruby_string.sub("^","**").to_s()
|
|
1046
|
+
|
|
1047
|
+
eval_binding = binding
|
|
1048
|
+
|
|
1049
|
+
inline_calculation_answer = eval_binding.eval(inline_calc_ruby_string)
|
|
1050
|
+
|
|
1051
|
+
inline_calculation_answer = inline_calculation_answer.to_s
|
|
1052
|
+
|
|
1053
|
+
if inline_calculation_answer.include?(".")
|
|
1054
|
+
|
|
1055
|
+
inline_calculation_answer = inline_calculation_answer.to_f.round(3).to_s
|
|
1056
|
+
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
current_row = current_row.sub(inline_calculation_string,inline_calculation_answer)
|
|
1060
|
+
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
input_file_contents[x] = current_row
|
|
1064
|
+
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
file_id = open(temporary_file_path, 'w')
|
|
1068
|
+
|
|
1069
|
+
file_id.write(input_file_contents.join)
|
|
1070
|
+
|
|
1071
|
+
file_id.close()
|
|
1072
|
+
|
|
1073
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1074
|
+
|
|
1075
|
+
return line_by_line_contents, temporary_file_path
|
|
1076
|
+
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
def resolve_inline_formatting(input_file_contents,temporary_file_path)
|
|
1080
|
+
|
|
1081
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1082
|
+
|
|
1083
|
+
locations = []
|
|
1084
|
+
|
|
1085
|
+
index = input_string.index(pattern)
|
|
1086
|
+
|
|
1087
|
+
while index != nil
|
|
1088
|
+
|
|
1089
|
+
locations << index
|
|
1090
|
+
|
|
1091
|
+
index = input_string.index(pattern,index+1)
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
return locations
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
document_as_string = input_file_contents.join
|
|
1102
|
+
|
|
1103
|
+
available_formatting = ["**","///","+*","+/","___","~~~"]
|
|
1104
|
+
|
|
1105
|
+
matching_formatting = {"**" => "\\textbf{","///" => "\\emph{" , "+*" => "\\mathbf{" , "+/" => "\\mathit{", "___" => "\\underline{","~~~" => "\\sout{"}
|
|
1106
|
+
|
|
1107
|
+
for x in 0...available_formatting.length
|
|
1108
|
+
|
|
1109
|
+
current_formatting = available_formatting[x]
|
|
1110
|
+
|
|
1111
|
+
location_of_current_formatting = find_all_matching_indices(document_as_string,current_formatting)
|
|
1112
|
+
|
|
1113
|
+
if location_of_current_formatting.length.modulo(2) == 0
|
|
1114
|
+
|
|
1115
|
+
for y in 0...((location_of_current_formatting.length)/2)
|
|
1116
|
+
|
|
1117
|
+
document_as_string = document_as_string.sub(current_formatting,matching_formatting[current_formatting])
|
|
1118
|
+
|
|
1119
|
+
document_as_string = document_as_string.sub(current_formatting,"}")
|
|
1120
|
+
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
end
|
|
1124
|
+
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
file_id = open(temporary_file_path, 'w')
|
|
1128
|
+
|
|
1129
|
+
file_id.write(document_as_string)
|
|
1130
|
+
|
|
1131
|
+
file_id.close()
|
|
1132
|
+
|
|
1133
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1134
|
+
|
|
1135
|
+
return line_by_line_contents, temporary_file_path
|
|
1136
|
+
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
def resolve_fenced_code_blocks(input_file_contents,temporary_file_path,fenced_code_blocks)
|
|
1140
|
+
|
|
1141
|
+
input_file_as_string = input_file_contents.join
|
|
1142
|
+
|
|
1143
|
+
for x in 0...fenced_code_blocks.length
|
|
1144
|
+
|
|
1145
|
+
fenced_code_block_string = "@@fenced_code_block[#{x+1}]"
|
|
1146
|
+
|
|
1147
|
+
replacement_string = fenced_code_blocks[x]
|
|
1148
|
+
|
|
1149
|
+
replacement_string = replacement_string.sub("###","\\begin{verbatim}")
|
|
1150
|
+
|
|
1151
|
+
replacement_string = replacement_string.sub("###","\\end{verbatim}")
|
|
1152
|
+
|
|
1153
|
+
input_file_as_string = input_file_as_string.sub(fenced_code_block_string,replacement_string)
|
|
1154
|
+
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
file_id = open(temporary_file_path, 'w')
|
|
1158
|
+
|
|
1159
|
+
file_id.write(input_file_as_string)
|
|
1160
|
+
|
|
1161
|
+
file_id.close()
|
|
1162
|
+
|
|
1163
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1164
|
+
|
|
1165
|
+
return line_by_line_contents, temporary_file_path
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
end
|
|
1169
|
+
|
|
1170
|
+
def resolve_inline_fenced_code(input_file_contents,temporary_file_path,inline_code_blocks)
|
|
1171
|
+
|
|
1172
|
+
input_file_as_string = input_file_contents.join
|
|
1173
|
+
|
|
1174
|
+
for x in 0...inline_code_blocks.length
|
|
1175
|
+
|
|
1176
|
+
fenced_code_block_string = "@@inline_code_block[#{x+1}]"
|
|
1177
|
+
|
|
1178
|
+
replacement_string = inline_code_blocks[x]
|
|
1179
|
+
|
|
1180
|
+
input_file_as_string = input_file_as_string.sub(fenced_code_block_string,replacement_string[2...-2])
|
|
1181
|
+
|
|
1182
|
+
end
|
|
1183
|
+
|
|
1184
|
+
file_id = open(temporary_file_path, 'w')
|
|
1185
|
+
|
|
1186
|
+
file_id.write(input_file_as_string)
|
|
1187
|
+
|
|
1188
|
+
file_id.close()
|
|
1189
|
+
|
|
1190
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1191
|
+
|
|
1192
|
+
return line_by_line_contents, temporary_file_path
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
def resolve_tex_packs(input_file_contents,temporary_file,preference_directory)
|
|
1199
|
+
|
|
1200
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1201
|
+
|
|
1202
|
+
locations = []
|
|
1203
|
+
|
|
1204
|
+
index = input_string.index(pattern)
|
|
1205
|
+
|
|
1206
|
+
while index != nil
|
|
1207
|
+
|
|
1208
|
+
locations << index
|
|
1209
|
+
|
|
1210
|
+
index = input_string.index(pattern,index+1)
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
end
|
|
1214
|
+
|
|
1215
|
+
return locations
|
|
1216
|
+
|
|
1217
|
+
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
default_texpack = [
|
|
1221
|
+
"\\usepackage{amsmath,amssymb,amsthm}\n\n",
|
|
1222
|
+
"\\usepackage[a4paper,margin = 1in]{geometry}\n\n",
|
|
1223
|
+
"\\usepackage{hyperref}\n\n",
|
|
1224
|
+
"\\usepackage[normalem]{ulem}\n\n",
|
|
1225
|
+
"\\usepackage{xcolor}\n\n",
|
|
1226
|
+
"\\usepackage{verbatim}\n\n",
|
|
1227
|
+
"\\usepackage{booktabs}\n\n",
|
|
1228
|
+
"\\usepackage{graphicx}\n\n",
|
|
1229
|
+
"\\usepackage{multicol}\n\n",
|
|
1230
|
+
"\\usepackage{cleveref}\n\n",
|
|
1231
|
+
"\\usepackage{siunitx}\n"]
|
|
1232
|
+
|
|
1233
|
+
end_of_preamble = 0
|
|
1234
|
+
|
|
1235
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
1236
|
+
|
|
1237
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
1238
|
+
|
|
1239
|
+
end
|
|
1240
|
+
|
|
1241
|
+
preamble = input_file_contents[0...end_of_preamble]
|
|
1242
|
+
|
|
1243
|
+
document_string = input_file_contents[end_of_preamble..-1].join
|
|
1244
|
+
|
|
1245
|
+
preamble_string = preamble.join
|
|
1246
|
+
|
|
1247
|
+
if !preamble_string.include?("$(importpack)") and !preamble_string.include?("\\usepackage")
|
|
1248
|
+
|
|
1249
|
+
default_texpack_string = default_texpack.join
|
|
1250
|
+
|
|
1251
|
+
documentclass_finder = preamble_string.index("\\documentclass")
|
|
1252
|
+
|
|
1253
|
+
extract_string = preamble_string[documentclass_finder..-1]
|
|
1254
|
+
|
|
1255
|
+
documentclass_end = extract_string.index("}")
|
|
1256
|
+
|
|
1257
|
+
documentclass_string = extract_string[0..documentclass_end]
|
|
1258
|
+
|
|
1259
|
+
replacement_string = documentclass_string + "\n\n" + default_texpack_string + "\n\n"
|
|
1260
|
+
|
|
1261
|
+
preamble_string = preamble_string.sub(documentclass_string,replacement_string)
|
|
1262
|
+
|
|
1263
|
+
elsif preamble_string.include?("$(importpack)")
|
|
1264
|
+
|
|
1265
|
+
importpack_locations = find_all_matching_indices(preamble_string,"$(importpack)")
|
|
1266
|
+
|
|
1267
|
+
for x in 0...importpack_locations.length
|
|
1268
|
+
|
|
1269
|
+
current_location = importpack_locations[x]
|
|
1270
|
+
|
|
1271
|
+
extract_string = preamble_string[current_location..-1]
|
|
1272
|
+
|
|
1273
|
+
importpack_end = extract_string.index("]")
|
|
1274
|
+
|
|
1275
|
+
importpack_string = extract_string[0..importpack_end]
|
|
1276
|
+
|
|
1277
|
+
importpack_string_split = importpack_string.split("[")
|
|
1278
|
+
|
|
1279
|
+
importpack_string_split = importpack_string_split[1].split("]")
|
|
1280
|
+
|
|
1281
|
+
importpack_name = importpack_string_split[0]
|
|
1282
|
+
|
|
1283
|
+
if !importpack_name.include?("\\")
|
|
1284
|
+
|
|
1285
|
+
importpack_path = preference_directory + importpack_name + ".texpack"
|
|
1286
|
+
|
|
1287
|
+
else
|
|
1288
|
+
|
|
1289
|
+
importpack_path = importpack_name
|
|
1290
|
+
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
texpack_file = read_file_line_by_line(importpack_path).join
|
|
1294
|
+
|
|
1295
|
+
preamble_string = preamble_string.sub(importpack_string,texpack_file)
|
|
1296
|
+
|
|
1297
|
+
|
|
1298
|
+
end
|
|
1299
|
+
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
file_id = open(temporary_file, 'w')
|
|
1303
|
+
|
|
1304
|
+
file_id.write(preamble_string + document_string)
|
|
1305
|
+
|
|
1306
|
+
file_id.close()
|
|
1307
|
+
|
|
1308
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1309
|
+
|
|
1310
|
+
return line_by_line_contents, temporary_file
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
def resolve_bare_urls(input_file_contents,temporary_file)
|
|
1316
|
+
|
|
1317
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1318
|
+
|
|
1319
|
+
locations = []
|
|
1320
|
+
|
|
1321
|
+
index = input_string.index(pattern)
|
|
1322
|
+
|
|
1323
|
+
while index != nil
|
|
1324
|
+
|
|
1325
|
+
locations << index
|
|
1326
|
+
|
|
1327
|
+
index = input_string.index(pattern,index+1)
|
|
1328
|
+
|
|
1329
|
+
|
|
1330
|
+
end
|
|
1331
|
+
|
|
1332
|
+
return locations
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
end
|
|
1336
|
+
|
|
1337
|
+
def modify_urls(input_url_string)
|
|
1338
|
+
|
|
1339
|
+
return_string = "\\url{#{input_url_string}}"
|
|
1340
|
+
|
|
1341
|
+
return return_string
|
|
1342
|
+
|
|
1343
|
+
end
|
|
1344
|
+
|
|
1345
|
+
input_file_as_string = input_file_contents.join
|
|
1346
|
+
|
|
1347
|
+
modified_input_string = input_file_as_string.dup
|
|
1348
|
+
|
|
1349
|
+
url_identifiers = ["http","www"]
|
|
1350
|
+
|
|
1351
|
+
replacements = ["@@http[]","@@www[]"]
|
|
1352
|
+
|
|
1353
|
+
identifier_matches = []
|
|
1354
|
+
|
|
1355
|
+
replacement_strings = []
|
|
1356
|
+
|
|
1357
|
+
for x in 0...url_identifiers.length
|
|
1358
|
+
|
|
1359
|
+
current_identifier = url_identifiers[x]
|
|
1360
|
+
|
|
1361
|
+
current_replacement = replacements[x]
|
|
1362
|
+
|
|
1363
|
+
current_replacement_split = current_replacement.split("]")
|
|
1364
|
+
|
|
1365
|
+
location_of_current_identifer = find_all_matching_indices(input_file_as_string,current_identifier)
|
|
1366
|
+
|
|
1367
|
+
current_identifier_matches = []
|
|
1368
|
+
|
|
1369
|
+
current_replacement_strings = []
|
|
1370
|
+
|
|
1371
|
+
for y in 0...location_of_current_identifer.length
|
|
1372
|
+
|
|
1373
|
+
current_location = location_of_current_identifer[y]
|
|
1374
|
+
|
|
1375
|
+
extract_string = input_file_as_string[current_location..-1]
|
|
1376
|
+
|
|
1377
|
+
url_extract = extract_string.split(" ",2)
|
|
1378
|
+
|
|
1379
|
+
current_identifier_matches << url_extract[0]
|
|
1380
|
+
|
|
1381
|
+
replacement_string = current_replacement_split[0] + (y+1).to_s + "]"
|
|
1382
|
+
|
|
1383
|
+
current_replacement_strings << replacement_string
|
|
1384
|
+
|
|
1385
|
+
modified_input_string = modified_input_string.sub(url_extract[0],replacement_string)
|
|
1386
|
+
|
|
1387
|
+
end
|
|
1388
|
+
|
|
1389
|
+
identifier_matches << current_identifier_matches
|
|
1390
|
+
|
|
1391
|
+
replacement_strings << current_replacement_strings
|
|
1392
|
+
|
|
1393
|
+
end
|
|
1394
|
+
|
|
1395
|
+
for x in 0...identifier_matches.length
|
|
1396
|
+
|
|
1397
|
+
current_identifer_match = identifier_matches[x]
|
|
1398
|
+
|
|
1399
|
+
replacement_string_array = replacement_strings[x]
|
|
1400
|
+
|
|
1401
|
+
for y in 0...current_identifer_match.length
|
|
1402
|
+
|
|
1403
|
+
urls = current_identifer_match[y]
|
|
1404
|
+
|
|
1405
|
+
interim_replacement = replacement_string_array[y]
|
|
1406
|
+
|
|
1407
|
+
replacement_urls = modify_urls(urls)
|
|
1408
|
+
|
|
1409
|
+
modified_input_string = modified_input_string.sub(interim_replacement,replacement_urls)
|
|
1410
|
+
|
|
1411
|
+
|
|
1412
|
+
end
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
file_id = open(temporary_file, 'w')
|
|
1418
|
+
|
|
1419
|
+
file_id.write(modified_input_string)
|
|
1420
|
+
|
|
1421
|
+
file_id.close()
|
|
1422
|
+
|
|
1423
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1424
|
+
|
|
1425
|
+
return line_by_line_contents, temporary_file
|
|
1426
|
+
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
def replace_descriptive_urls(input_file_contents,temporary_file)
|
|
1430
|
+
|
|
1431
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1432
|
+
|
|
1433
|
+
locations = []
|
|
1434
|
+
|
|
1435
|
+
index = input_string.index(pattern)
|
|
1436
|
+
|
|
1437
|
+
while index != nil
|
|
1438
|
+
|
|
1439
|
+
locations << index
|
|
1440
|
+
|
|
1441
|
+
index = input_string.index(pattern,index+1)
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
end
|
|
1445
|
+
|
|
1446
|
+
return locations
|
|
1447
|
+
|
|
1448
|
+
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
def process_urls(input_string)
|
|
1452
|
+
|
|
1453
|
+
core_string = input_string[2...-1]
|
|
1454
|
+
|
|
1455
|
+
split_string = core_string.split("=>")
|
|
1456
|
+
|
|
1457
|
+
return "\\href{#{split_string[1].strip}}{#{split_string[0].strip}}"
|
|
1458
|
+
|
|
1459
|
+
end
|
|
1460
|
+
|
|
1461
|
+
input_file_as_string = input_file_contents.join
|
|
1462
|
+
|
|
1463
|
+
modified_input_string = input_file_as_string.dup
|
|
1464
|
+
|
|
1465
|
+
descriptive_url_locations = find_all_matching_indices(input_file_as_string,"*[")
|
|
1466
|
+
|
|
1467
|
+
replacement_string = "@@descript[]"
|
|
1468
|
+
|
|
1469
|
+
replacement_urls = []
|
|
1470
|
+
|
|
1471
|
+
replacement_strings = []
|
|
1472
|
+
|
|
1473
|
+
for x in 0...descriptive_url_locations.length
|
|
1474
|
+
|
|
1475
|
+
current_location = descriptive_url_locations[x]
|
|
1476
|
+
|
|
1477
|
+
extract_string = input_file_as_string[current_location..-1]
|
|
1478
|
+
|
|
1479
|
+
end_finder = extract_string.index("]")
|
|
1480
|
+
|
|
1481
|
+
descriptive_url = extract_string[0..end_finder]
|
|
1482
|
+
|
|
1483
|
+
replacement_url = process_urls(descriptive_url)
|
|
1484
|
+
|
|
1485
|
+
replacement_urls << replacement_url
|
|
1486
|
+
|
|
1487
|
+
current_replacement_string = replacement_string.sub("]","#{x+1}]")
|
|
1488
|
+
|
|
1489
|
+
replacement_strings << current_replacement_string
|
|
1490
|
+
|
|
1491
|
+
modified_input_string = modified_input_string.sub(descriptive_url,current_replacement_string)
|
|
1492
|
+
|
|
1493
|
+
end
|
|
1494
|
+
|
|
1495
|
+
to_be_replaced = [replacement_strings,replacement_urls]
|
|
1496
|
+
|
|
1497
|
+
file_id = open(temporary_file, 'w')
|
|
1498
|
+
|
|
1499
|
+
file_id.write(modified_input_string)
|
|
1500
|
+
|
|
1501
|
+
file_id.close()
|
|
1502
|
+
|
|
1503
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1504
|
+
|
|
1505
|
+
return line_by_line_contents, temporary_file, to_be_replaced
|
|
1506
|
+
|
|
1507
|
+
end
|
|
1508
|
+
|
|
1509
|
+
def resolve_descriptive_urls(input_file_contents,temporary_file,replacement_array)
|
|
1510
|
+
|
|
1511
|
+
input_file_as_string = input_file_contents.join
|
|
1512
|
+
|
|
1513
|
+
modified_input_string = input_file_as_string.dup
|
|
1514
|
+
|
|
1515
|
+
interim_strings = replacement_array[0]
|
|
1516
|
+
|
|
1517
|
+
descriptive_urls = replacement_array[1]
|
|
1518
|
+
|
|
1519
|
+
for x in 0...interim_strings.length
|
|
1520
|
+
|
|
1521
|
+
current_interim_string = interim_strings[x]
|
|
1522
|
+
|
|
1523
|
+
current_descriptive_url = descriptive_urls[x]
|
|
1524
|
+
|
|
1525
|
+
modified_input_string = modified_input_string.sub(current_interim_string,current_descriptive_url)
|
|
1526
|
+
|
|
1527
|
+
end
|
|
1528
|
+
|
|
1529
|
+
file_id = open(temporary_file, 'w')
|
|
1530
|
+
|
|
1531
|
+
file_id.write(modified_input_string)
|
|
1532
|
+
|
|
1533
|
+
file_id.close()
|
|
1534
|
+
|
|
1535
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1536
|
+
|
|
1537
|
+
return line_by_line_contents, temporary_file
|
|
1538
|
+
|
|
1539
|
+
end
|
|
1540
|
+
|
|
1541
|
+
#The following methods implements some features of Smarty Pants
|
|
1542
|
+
|
|
1543
|
+
#http://daringfireball.net/projects/smartypants/
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
def resolve_double_quotes(input_file_contents,temporary_file)
|
|
1547
|
+
|
|
1548
|
+
#This feature implements the double quotes features in smarty pants
|
|
1549
|
+
|
|
1550
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1551
|
+
|
|
1552
|
+
locations = []
|
|
1553
|
+
|
|
1554
|
+
index = input_string.index(pattern)
|
|
1555
|
+
|
|
1556
|
+
while index != nil
|
|
1557
|
+
|
|
1558
|
+
locations << index
|
|
1559
|
+
|
|
1560
|
+
index = input_string.index(pattern,index+1)
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
end
|
|
1564
|
+
|
|
1565
|
+
return locations
|
|
1566
|
+
|
|
1567
|
+
|
|
1568
|
+
end
|
|
1569
|
+
|
|
1570
|
+
input_file_as_string = input_file_contents.join
|
|
1571
|
+
|
|
1572
|
+
modified_input_string = input_file_as_string.dup
|
|
1573
|
+
|
|
1574
|
+
opening_quotes_locations = find_all_matching_indices(input_file_as_string,"\"")
|
|
1575
|
+
|
|
1576
|
+
if opening_quotes_locations.length.modulo(2) == 0
|
|
1577
|
+
|
|
1578
|
+
for x in 0...(opening_quotes_locations.length)/2
|
|
1579
|
+
|
|
1580
|
+
modified_input_string = modified_input_string.sub("\"","``")
|
|
1581
|
+
|
|
1582
|
+
modified_input_string = modified_input_string.sub("\"","''")
|
|
1583
|
+
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
end
|
|
1587
|
+
|
|
1588
|
+
file_id = open(temporary_file, 'w')
|
|
1589
|
+
|
|
1590
|
+
file_id.write(modified_input_string)
|
|
1591
|
+
|
|
1592
|
+
file_id.close()
|
|
1593
|
+
|
|
1594
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1595
|
+
|
|
1596
|
+
return line_by_line_contents, temporary_file
|
|
1597
|
+
|
|
1598
|
+
end
|
|
1599
|
+
|
|
1600
|
+
def convert_to_latex_commands(input_file_contents,temporary_file)
|
|
1601
|
+
|
|
1602
|
+
#This method is designed to be more general than just the features available in smarty pants
|
|
1603
|
+
|
|
1604
|
+
#This method currently implements ellipses
|
|
1605
|
+
|
|
1606
|
+
vanilla_commands = ["...."]
|
|
1607
|
+
|
|
1608
|
+
latex_commands = {"...." => "\\ldots"}
|
|
1609
|
+
|
|
1610
|
+
input_file_as_string = input_file_contents.join
|
|
1611
|
+
|
|
1612
|
+
modified_input_string = input_file_as_string.dup
|
|
1613
|
+
|
|
1614
|
+
vanilla_commands.each do |command|
|
|
1615
|
+
|
|
1616
|
+
modified_input_string = modified_input_string.gsub(command,latex_commands[command])
|
|
1617
|
+
|
|
1618
|
+
end
|
|
1619
|
+
|
|
1620
|
+
file_id = open(temporary_file, 'w')
|
|
1621
|
+
|
|
1622
|
+
file_id.write(modified_input_string)
|
|
1623
|
+
|
|
1624
|
+
file_id.close()
|
|
1625
|
+
|
|
1626
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1627
|
+
|
|
1628
|
+
return line_by_line_contents, temporary_file
|
|
1629
|
+
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
#The following methods are for writing the output LaTex code.
|
|
1633
|
+
|
|
1634
|
+
def write_latex_file(input_file_contents,temporary_file,input_val_file)
|
|
1635
|
+
|
|
1636
|
+
input_file_as_string = input_file_contents.join
|
|
1637
|
+
|
|
1638
|
+
File.delete(temporary_file)
|
|
1639
|
+
|
|
1640
|
+
output_latex_file_path = input_val_file.split(".tex")
|
|
1641
|
+
|
|
1642
|
+
output_latex_file_path = output_latex_file_path[0] + ".tex"
|
|
1643
|
+
|
|
1644
|
+
file_id = open(output_latex_file_path, 'w')
|
|
1645
|
+
|
|
1646
|
+
file_id.write(input_file_as_string)
|
|
1647
|
+
|
|
1648
|
+
file_id.close()
|
|
1649
|
+
|
|
1650
|
+
end
|
|
1651
|
+
|
|
1652
|
+
#The following method compiles the output .tex file into PDF and then overwrites the .tex file with the
|
|
1653
|
+
#original content
|
|
1654
|
+
|
|
1655
|
+
def compile_to_pdf(input_file_path,raw_file_as_string)
|
|
1656
|
+
|
|
1657
|
+
#The method first compiles the .tex file into PDF using PDFLatex
|
|
1658
|
+
|
|
1659
|
+
latex_compiler_output = `pdflatex -interaction=nonstopmode #{input_file_path}`
|
|
1660
|
+
|
|
1661
|
+
file_id = open(input_file_path,'w')
|
|
1662
|
+
|
|
1663
|
+
file_id.write(raw_file_as_string)
|
|
1664
|
+
|
|
1665
|
+
file_id.close()
|
|
1666
|
+
|
|
1667
|
+
return latex_compiler_output
|
|
1668
|
+
|
|
1669
|
+
end
|
|
1670
|
+
|
|
1671
|
+
|
|
1672
|
+
#The following methods are used only for testing and debugging purposes
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
def print_list(input_list)
|
|
1676
|
+
|
|
1677
|
+
#This method will print each line of the inputted list. This method is usually used to test and see whether other parts of
|
|
1678
|
+
#the compiler are working correctly
|
|
1679
|
+
|
|
1680
|
+
length_of_list = input_list.length
|
|
1681
|
+
|
|
1682
|
+
for x in 0...length_of_list
|
|
1683
|
+
|
|
1684
|
+
current_item = input_list[x]
|
|
1685
|
+
|
|
1686
|
+
print(current_item)
|
|
1687
|
+
|
|
1688
|
+
end
|
|
1689
|
+
|
|
1690
|
+
end
|
|
1691
|
+
|
|
1692
|
+
|
|
1693
|
+
line_by_line_file = read_file_line_by_line(input_val_file)
|
|
1694
|
+
|
|
1695
|
+
raw_file = line_by_line_file.dup
|
|
1696
|
+
|
|
1697
|
+
line_by_line_file, temp_file, fenced_code_blocks, preferred_directory = replace_fenced_code_block(line_by_line_file,input_val_file)
|
|
1698
|
+
|
|
1699
|
+
line_by_line_file, temp_file, inline_code_blocks = replace_inline_fenced_code(line_by_line_file,temp_file)
|
|
1700
|
+
|
|
1701
|
+
line_by_line_file, temp_file = resolve_comments(line_by_line_file,temp_file)
|
|
1702
|
+
|
|
1703
|
+
line_by_line_file, temp_file = resolve_constants(line_by_line_file, temp_file)
|
|
1704
|
+
|
|
1705
|
+
line_by_line_file, temp_file = resolve_formatted_text_blocks(line_by_line_file,temp_file)
|
|
1706
|
+
|
|
1707
|
+
line_by_line_file, temp_file = resolve_formulas(line_by_line_file,temp_file)
|
|
1708
|
+
|
|
1709
|
+
line_by_line_file, temp_file = resolve_inline_calculations(line_by_line_file,temp_file)
|
|
1710
|
+
|
|
1711
|
+
line_by_line_file, temp_file = resolve_inline_formatting(line_by_line_file,temp_file)
|
|
1712
|
+
|
|
1713
|
+
line_by_line_file, temp_file = resolve_tex_packs(line_by_line_file,temp_file,preferred_directory)
|
|
1714
|
+
|
|
1715
|
+
line_by_line_file, temp_file, replacement_array = replace_descriptive_urls(line_by_line_file,temp_file)
|
|
1716
|
+
|
|
1717
|
+
line_by_line_file, temp_file = resolve_bare_urls(line_by_line_file,temp_file)
|
|
1718
|
+
|
|
1719
|
+
line_by_line_file, temp_file = resolve_descriptive_urls(line_by_line_file,temp_file,replacement_array)
|
|
1720
|
+
|
|
1721
|
+
line_by_line_file, temp_file = resolve_double_quotes(line_by_line_file,temp_file)
|
|
1722
|
+
|
|
1723
|
+
line_by_line_file, temp_file = convert_to_latex_commands(line_by_line_file,temp_file)
|
|
1724
|
+
|
|
1725
|
+
line_by_line_file, temp_file = resolve_fenced_code_blocks(line_by_line_file,temp_file,fenced_code_blocks)
|
|
1726
|
+
|
|
1727
|
+
line_by_line_file, temp_file = resolve_inline_fenced_code(line_by_line_file,temp_file,inline_code_blocks)
|
|
1728
|
+
|
|
1729
|
+
write_latex_file(line_by_line_file,temp_file,input_val_file)
|
|
1730
|
+
|
|
1731
|
+
pdflatex_output = compile_to_pdf(input_val_file,raw_file.join)
|
|
1732
|
+
|
|
1733
|
+
return pdflatex_output
|
|
1734
|
+
|
|
1735
|
+
end
|
|
1736
|
+
|
|
1737
|
+
#This script creates a windows executable using the Ocra gem and a mac
|
|
1738
|
+
#version using shabang syntax.
|
|
1739
|
+
|
|
1740
|
+
def create_executable(input_file)
|
|
1741
|
+
|
|
1742
|
+
def read_file_line_by_line(input_path)
|
|
1743
|
+
|
|
1744
|
+
file_id = open(input_path)
|
|
1745
|
+
|
|
1746
|
+
file_line_by_line = file_id.readlines()
|
|
1747
|
+
|
|
1748
|
+
file_id.close
|
|
1749
|
+
|
|
1750
|
+
return file_line_by_line
|
|
1751
|
+
|
|
1752
|
+
end
|
|
1753
|
+
|
|
1754
|
+
windows_output = `ocra --add-all-core #{input_file}`
|
|
1755
|
+
|
|
1756
|
+
mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)
|
|
1757
|
+
|
|
1758
|
+
mac_file_path = input_file.sub(".rb","")
|
|
1759
|
+
|
|
1760
|
+
file_id = open(mac_file_path,"w")
|
|
1761
|
+
|
|
1762
|
+
file_id.write(mac_file_contents.join)
|
|
1763
|
+
|
|
1764
|
+
file_id.close
|
|
1765
|
+
|
|
1766
|
+
end
|
|
1767
|
+
|
|
1768
|
+
def create_mac_executable(input_file)
|
|
1769
|
+
|
|
1770
|
+
def read_file_line_by_line(input_path)
|
|
1771
|
+
|
|
1772
|
+
file_id = open(input_path)
|
|
1773
|
+
|
|
1774
|
+
file_line_by_line = file_id.readlines()
|
|
1775
|
+
|
|
1776
|
+
file_id.close
|
|
1777
|
+
|
|
1778
|
+
return file_line_by_line
|
|
1779
|
+
|
|
1780
|
+
end
|
|
1781
|
+
|
|
1782
|
+
mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)
|
|
1783
|
+
|
|
1784
|
+
mac_file_path = input_file.sub(".rb", "")
|
|
1785
|
+
|
|
1786
|
+
file_id = open(mac_file_path, "w")
|
|
1787
|
+
|
|
1788
|
+
file_id.write(mac_file_contents.join)
|
|
1789
|
+
|
|
1790
|
+
file_id.close
|
|
1791
|
+
|
|
1792
|
+
end
|
|
1793
|
+
|
|
1794
|
+
options = {}
|
|
1795
|
+
|
|
1796
|
+
OptionParser.new do |opts|
|
|
1797
|
+
opts.banner = "Usage: vanilla [options] TEX_FILE"
|
|
1798
|
+
|
|
1799
|
+
opts.on("-c", "--compile FILE", "Compile to PDF") do |file|
|
|
1800
|
+
current_directory = Dir.pwd
|
|
1801
|
+
file_path = current_directory + "/" + file
|
|
1802
|
+
latex_compiler_output = start_compile(file_path)
|
|
1803
|
+
puts latex_compiler_output
|
|
1804
|
+
|
|
1805
|
+
end
|
|
1806
|
+
|
|
1807
|
+
opts.on("-b", "--build FILE", "Builds Itself") do |file|
|
|
1808
|
+
|
|
1809
|
+
file_path = Dir.pwd + "/src/vanilla.rb"
|
|
1810
|
+
|
|
1811
|
+
create_mac_executable(file_path)
|
|
1812
|
+
|
|
1813
|
+
FileUtils.mv("#{file_path[0...-3]}", "#{Dir.pwd}/bin/vanilla")
|
|
1814
|
+
|
|
1815
|
+
puts "Build Successful!"
|
|
1816
|
+
|
|
1817
|
+
end
|
|
1818
|
+
|
|
1819
|
+
end.parse!
|