Package docs :: Package latex :: Module fetch_docstrings
[hide private]
[frames] | no frames]

Source Code for Module docs.latex.fetch_docstrings

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2005-2014 Edward d'Auvergne                                   # 
   4  #                                                                             # 
   5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
   6  #                                                                             # 
   7  # This program is free software: you can redistribute it and/or modify        # 
   8  # it under the terms of the GNU General Public License as published by        # 
   9  # the Free Software Foundation, either version 3 of the License, or           # 
  10  # (at your option) any later version.                                         # 
  11  #                                                                             # 
  12  # This program is distributed in the hope that it will be useful,             # 
  13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
  15  # GNU General Public License for more details.                                # 
  16  #                                                                             # 
  17  # You should have received a copy of the GNU General Public License           # 
  18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
  19  #                                                                             # 
  20  ############################################################################### 
  21   
  22  # Module docstring. 
  23  """User function definition conversion to LaTeX for the relax manual.""" 
  24   
  25  # Python module imports. 
  26  from os import sep 
  27  from os.path import dirname 
  28  from re import search 
  29  from string import ascii_letters, ascii_lowercase, punctuation, whitespace 
  30  import sys 
  31   
  32  # Add the path to the relax base directory. 
  33  sys.path.append(sys.path[0]) 
  34  sys.path[0] = '../..' 
  35   
  36  # relax module imports. 
  37  from graphics import fetch_icon 
  38  import user_functions 
  39  from user_functions.data import Uf_info; uf_info = Uf_info() 
  40  from user_functions.data import Uf_tables; uf_tables = Uf_tables() 
  41   
  42   
  43  # Set up the user functions. 
  44  user_functions.initialise() 
  45   
  46   
47 -class Fetch_docstrings:
48 - def __init__(self, file='docstring.tex'):
49 """Fetch all the docstrings of the user functions and format them LaTeX style.""" 50 51 # Initialise some variables. 52 self.in_quote = False 53 self.table_count = 1 54 self.uf_table_labels = [] 55 self.path = dirname(file) 56 57 # Set up the words to index. 58 self.index_entries() 59 60 # Open the LaTeX file. 61 self.file = open(file, 'w') 62 63 # Loop over the user functions. 64 uf_names = [] 65 for self.uf_name, self.uf in uf_info.uf_loop(): 66 # Add to the list. 67 uf_names.append(self.uf_name) 68 # The user function class. 69 self.uf_class = None 70 if search('\.', self.uf_name): 71 # Split up the name. 72 class_name, uf_name = self.uf_name.split('.') 73 74 # Get the user function class data object. 75 self.uf_class = uf_info.get_class(class_name) 76 77 # Reset the table count for each user function. 78 self.uf_table_count = 1 79 80 # Printout. 81 sys.stdout.write("User function: %s().\n" % self.uf_name) 82 83 # Build and write out the various sections, as needed. 84 self.build_uf() 85 self.build_synopsis() 86 self.build_arg_defaults() 87 self.build_kargs() 88 self.build_description() 89 90 # Close the LaTeX file. 91 self.file.close() 92 93 # Create the relax lstlisting definition. 94 self.script_definitions(uf_names)
95 96
97 - def break_functions(self, text):
98 """Allow the function text to be broken nicely across lines. 99 100 The '\' character will be added later by the latex_special_chars() method. 101 """ 102 103 # Allow line breaks after the opening bracket. 104 text = text.replace("(", "(\linebreak[0]") 105 106 # Allow line breaks after periods (but not in numbers). 107 for char in ascii_letters: 108 text = text.replace(".%s" % char, ".\linebreak[0]%s" % char) 109 110 # Allow line breaks after equal signs. 111 text = text.replace("=", "=\linebreak[0]") 112 113 # Remove the backslash to prevent is processing. 114 text = text.replace("\linebreak", "linebreak") 115 116 # Return the modified text. 117 return text
118 119
120 - def build_arg_defaults(self):
121 """Create the user function argument default section.""" 122 123 # The section heading. 124 self.file.write("\subsubsection{Defaults}\n\n") 125 126 # Initialise the text. 127 text = "(" 128 129 # The keyword args. 130 for i in range(len(self.uf.kargs)): 131 # Comma separation. 132 if i >= 1: 133 text += ", " 134 135 # Add the arg. 136 text += "%s=%s" % (self.uf.kargs[i]['name'], repr(self.uf.kargs[i]['default'])) 137 138 # The end. 139 text += ")" 140 141 # LaTeX formatting. 142 text = self.break_functions(text) 143 text = self.latex_quotes(text) 144 text = self.latex_special_chars(text) 145 146 # Write to file. 147 self.file.write("\\begin{flushleft}\n") 148 self.file.write("\\textsf{\\textbf{%s}%s}\n" % (self.latex_special_chars(self.break_functions(self.uf_name)), text)) 149 self.file.write("\\end{flushleft}\n\n\n")
150 151
152 - def build_description(self):
153 """Create the user function argument default section.""" 154 155 # Loop over the sections. 156 for i in range(len(self.uf.desc)): 157 # Alias the description. 158 desc = self.uf.desc[i] 159 160 # The section heading. 161 self.file.write("\subsubsection{%s}\n\n" % desc.get_title()) 162 163 # Loop over the documentation elements. 164 for type, element in desc.element_loop(): 165 # A paragraph. 166 if type == 'paragraph': 167 self.write_paragraph(element) 168 169 # Verbatim text. 170 elif type == 'verbatim': 171 self.write_verbatim(element) 172 173 # A list. 174 elif type == 'list': 175 self.write_list(element) 176 177 # An itemised list. 178 elif type == 'item list': 179 self.write_item_list(element) 180 181 # A table. 182 elif type == 'table': 183 self.write_table(element) 184 185 # A prompt example. 186 elif type == 'prompt': 187 self.write_prompt_example(element)
188 189 190
191 - def build_kargs(self):
192 """Create the user function keyword argument section.""" 193 194 # No keyword args, so do nothing. 195 if not len(self.uf.kargs): 196 return 197 198 # The section heading. 199 self.file.write("\subsubsection{Keyword arguments}\n\n") 200 201 # The keyword args. 202 for i in range(len(self.uf.kargs)): 203 # LaTeX formatting. 204 arg = self.latex_special_chars(self.uf.kargs[i]['name']) 205 text = self.latex_special_chars(self.uf.kargs[i]['desc']) 206 text = self.latex_formatting(text) 207 text = self.word_formatting(text, bold=False) 208 209 # Write to file. 210 self.file.write("\\hspace{3 mm}\\keyword{%s:} %s\n\n" % (arg, text)) 211 212 # Empty line to end with. 213 self.file.write("\n")
214 215
216 - def build_synopsis(self):
217 """Create the user function synopsis.""" 218 219 # The section heading. 220 self.file.write("\subsubsection{Synopsis}\n\n") 221 222 # The text. 223 text = self.uf.title 224 225 # LaTeX formatting. 226 text = self.latex_special_chars(text) 227 text = self.latex_formatting(text) 228 text = self.word_formatting(text, bold=False) 229 230 # Write to file. 231 self.file.write(text + '\n\n\n')
232 233
234 - def build_uf(self):
235 """Create the user function sectioning.""" 236 237 # Some whitespace. 238 self.file.write("\n\n") 239 240 # Start a new column for each user function and add a rule to the top. 241 self.file.write("\\pagebreak[4]\n") 242 self.file.write("\\rule{\columnwidth}{1pt}\n") 243 244 # The title (with less spacing). 245 self.file.write("\\vspace{-20pt}\n") 246 self.uf_name_latex = self.uf_name 247 248 # LaTeX formatting. 249 self.uf_name_latex = self.latex_special_chars(self.uf_name_latex) 250 self.uf_name_latex = self.word_formatting(self.uf_name_latex, bold=True) 251 252 # Allow for hyphenation. 253 self.uf_name_latex = self.uf_name_latex.replace('.', '\-.') 254 self.uf_name_latex = self.uf_name_latex.replace('\_', '\-\_') 255 256 # Write out the title (with label). 257 self.file.write("\subsection{%s} \label{uf: %s}\n" % (self.uf_name_latex, self.uf_name)) 258 259 # Add the user function class icon. 260 if self.uf_class: 261 icon = fetch_icon(self.uf_class.gui_icon, size='128x128', format=None, sep='/', full_path=False) 262 if icon: 263 self.file.write("\includegraphics[bb=0 0 18 18]{%s} \hfill " % icon) 264 else: 265 self.file.write("\hfill ") 266 267 # Add the user function icon. 268 icon = fetch_icon(self.uf.gui_icon, size='128x128', format=None, sep='/', full_path=False) 269 if icon: 270 self.file.write("\includegraphics[bb=0 0 18 18]{%s}\n" % icon) 271 else: 272 self.file.write("\n") 273 274 # End. 275 self.file.write("\n")
276 277
278 - def indexing(self, index, bold=False):
279 """Insert index marks into the text, word by word. 280 281 @param index: The index of the word in the self.words data structure. 282 @type index: int 283 @keyword bold: A flag which if True will cause the index entries to be in bold font. 284 @type bold: bool 285 """ 286 287 # End string. 288 if bold: 289 end_string = '|textbf}' 290 else: 291 end_string = '}' 292 293 # Loop over the indices. 294 for i in range(len(self.entries)): 295 # Find triple word entries. 296 if index+2 < len(self.words) and self.entries[i][2] == 3 and search(self.entries[i][0], self.words[index] + ' ' + self.words[index+1] + ' ' + self.words[index+2]): 297 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string 298 299 # Find double word entries. 300 elif index+1 < len(self.words) and self.entries[i][2] == 2 and search(self.entries[i][0], self.words[index] + ' ' + self.words[index+1]): 301 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string 302 303 # Find single word entries. 304 elif self.entries[i][2] == 1 and search(self.entries[i][0], self.words[index]): 305 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
306 307
308 - def index_entries(self):
309 """Function for returning a data structure containing all words which should be indexed.""" 310 311 # Initialise. 312 self.entries = [] 313 314 # The index entries (where to index and the index name). 315 ######################################################## 316 317 self.entries.append(['AIC', 'model selection!AIC']) 318 self.entries.append(['AICc', 'model selection!AICc']) 319 self.entries.append(['angle', 'angles']) 320 self.entries.append(['anisotropic', 'diffusion!anisotropic']) 321 self.entries.append(['ANOVA', 'model selection!ANOVA']) 322 self.entries.append(['asymmetric', 'diffusion!ellipsoid (asymmetric)']) 323 self.entries.append(['axially symmetric', 'diffusion!spheroid (axially symmetric)']) 324 325 self.entries.append(['BIC', 'model selection!BIC']) 326 self.entries.append(['BFGS', 'optimisation!algorithm!BFGS']) 327 self.entries.append(['bond length', 'bond length']) 328 self.entries.append(['bootstrap', 'model selection!bootstrap']) 329 self.entries.append(['bound', 'parameter!bounds']) 330 self.entries.append(['Brownian', 'diffusion!Brownian']) 331 self.entries.append(['bzip2', 'compression!bzip2']) 332 333 self.entries.append(['cauchy', 'optimisation!algorithm!Cauchy point']) 334 self.entries.append(['CG-Steihaug', 'optimisation!algorithm!CG-Steihaug']) 335 self.entries.append(['chemical exchange', 'chemical exchange']) 336 self.entries.append(['chi-squared', 'chi-squared']) 337 self.entries.append(['compression', 'compression']) 338 self.entries.append(['conjugate gradient', 'optimisation!algorithm!conjugate gradient']) 339 self.entries.append(['constraint', 'constraint']) 340 self.entries.append(['copy', 'copy']) 341 self.entries.append(['correlation time', 'correlation time']) 342 self.entries.append(['cross-validation', 'model selection!cross-validation']) 343 344 self.entries.append(['dasha', 'software!Dasha']) 345 self.entries.append(['Dasha', 'software!Dasha']) 346 self.entries.append(['delete', 'delete']) 347 self.entries.append(['diffusion tensor', 'diffusion!tensor']) 348 self.entries.append(['display', 'display']) 349 self.entries.append(['dogleg', 'optimisation!algorithm!dogleg']) 350 351 self.entries.append(['eigenvalue', 'eigenvalues']) 352 self.entries.append(['elimination', 'model elimination']) 353 self.entries.append(['ellipsoid', 'diffusion!ellipsoid (asymmetric)']) 354 self.entries.append(['Euler angle', 'Euler angles']) 355 self.entries.append(['exact trust region', 'optimisation!algorithm!exact trust region']) 356 357 self.entries.append(['Fletcher-Reeves', 'optimisation!algorithm!Fletcher-Reeves']) 358 self.entries.append(['floating point', 'floating point number']) 359 360 self.entries.append(['grace', 'software!Grace']) 361 self.entries.append(['Grace', 'software!Grace']) 362 self.entries.append(['gzip', 'compression!gzip']) 363 364 self.entries.append(['Hestenes-Stiefel', 'optimisation!algorithm!Hestenes-Stiefel']) 365 self.entries.append(['hypothesis testing', 'model selection!hypothesis testing']) 366 367 self.entries.append(['isotropic', 'diffusion!sphere (isotropic)']) 368 369 self.entries.append(['Levenberg-Marquardt', 'optimisation!algorithm!Levenberg-Marquardt']) 370 self.entries.append(['limit', 'parameter!limit']) 371 372 self.entries.append(['map', 'map']) 373 self.entries.append(['method of [Mm]ultipliers', 'optimisation!constraint algorithm!Method of Multipliers']) 374 self.entries.append(['minimise', 'optimisation']) 375 self.entries.append(['minimisation', 'optimisation']) 376 self.entries.append(['model elimination', 'model elimination']) 377 self.entries.append(['modelfree4', 'software!Modelfree']) 378 self.entries.append(['Modelfree4', 'software!Modelfree']) 379 self.entries.append(['modelling', 'modelling']) 380 self.entries.append(['molecule', 'molecule']) 381 self.entries.append(['molmol', 'software!MOLMOL']) 382 self.entries.append(['Molmol', 'software!MOLMOL']) 383 384 self.entries.append(['opendx', 'software!OpenDX']) 385 self.entries.append(['OpenDX', 'software!OpenDX']) 386 self.entries.append(['optimise', 'optimise']) 387 self.entries.append(['order parameter', 'order parameter']) 388 389 self.entries.append(['newton', 'optimisation!algorithm!Newton']) 390 self.entries.append(['newton-CG', 'optimisation!algorithm!Newton conjugate gradient']) 391 self.entries.append(['NMR', 'NMR']) 392 393 self.entries.append(['PDB', 'PDB']) 394 self.entries.append(['Polak-Ribi.*re', 'optimisation!algorithm!Polak-Ribiere@Polak-Ribi\`ere']) 395 self.entries.append(['Polak-Ribi.*re +', 'optimisation!algorithm!Polak-Ribiere@Polak-Ribi\`ere +']) 396 self.entries.append(['plot', 'plot']) 397 self.entries.append(['python', 'Python']) 398 399 self.entries.append(['read', 'read']) 400 self.entries.append(['regular expression', 'regular expression']) 401 self.entries.append(['relaxation', 'relaxation']) 402 self.entries.append(['rotation', 'rotation']) 403 404 self.entries.append(['sequence', 'sequence']) 405 self.entries.append(['script', 'scripting!script file']) 406 self.entries.append(['scripting', 'scripting']) 407 self.entries.append(['simplex', 'optimisation!algorithm!Nelder-Mead simplex']) 408 self.entries.append(['sphere', 'diffusion!sphere (isotropic)']) 409 self.entries.append(['spheroid', 'diffusion!spheroid (axially symmetric)']) 410 self.entries.append(['sparky', 'software!Sparky']) 411 self.entries.append(['Sparky', 'software!Sparky']) 412 self.entries.append(['steepest descent', 'optimisation!algorithm!steepest descent']) 413 414 self.entries.append(['tar', 'tar']) 415 416 self.entries.append(['uncompressed', 'compression!uncompressed']) 417 418 self.entries.append(['write', 'write']) 419 420 self.entries.append(['xeasy', 'software!XEasy']) 421 self.entries.append(['Xeasy', 'software!XEasy']) 422 self.entries.append(['XEasy', 'software!XEasy']) 423 424 # Modifications. 425 for i in range(len(self.entries)): 426 # Count the number of words. 427 self.entries[i].append(len(self.entries[i][0].split(' '))) 428 429 # Accept capitalisation. 430 if search(self.entries[i][0][0], ascii_lowercase): 431 self.entries[i][0] = '[' + self.entries[i][0][0].upper() + self.entries[i][0][0] + ']' + self.entries[i][0][1:] 432 433 # Add a carrot to the start of the match string. 434 self.entries[i][0] = '^' + self.entries[i][0] 435 436 # Reverse the subarray in prepartion for sorting. 437 self.entries[i].reverse() 438 439 # Reverse sort by word count. 440 self.entries.sort(reverse=1) 441 for i in range(len(self.entries)): 442 self.entries[i].reverse()
443 444
445 - def latex_formatting(self, string):
446 """Function for handling LaTeX maths environments.""" 447 448 # Angstrom. 449 string = self.safe_replacement(string, 'Angstroms', '\AA') 450 string = self.safe_replacement(string, 'Angstrom', '\AA') 451 452 # Pi. 453 string = self.safe_replacement(string, 'pi', '$\pi$') 454 455 # Less than. 456 string = string.replace(' < ', ' $<$ ') 457 458 # Less than or equal. 459 string = string.replace(' <= ', ' $\le$ ') 460 461 # Much less than. 462 string = string.replace(' << ', ' $<<$ ') 463 464 # Greater than. 465 string = string.replace(' > ', ' $>$ ') 466 467 # Greater than or equal. 468 string = string.replace(' >= ', ' $\ge$ ') 469 470 # Much greater than. 471 string = string.replace(' >> ', ' $>>$ ') 472 473 # 1st, 2nd, etc. 474 string = string.replace('1st', '1$^{\mathrm{st}}$') 475 string = string.replace('2nd', '2$^{\mathrm{nd}}$') 476 string = string.replace('3rd', '3$^{\mathrm{rd}}$') 477 string = string.replace('4th', '4$^{\mathrm{th}}$') 478 string = string.replace('5th', '5$^{\mathrm{th}}$') 479 string = string.replace('6th', '6$^{\mathrm{th}}$') 480 string = string.replace('7th', '7$^{\mathrm{th}}$') 481 string = string.replace('8th', '8$^{\mathrm{th}}$') 482 string = string.replace('9th', '9$^{\mathrm{th}}$') 483 string = string.replace('0th', '0$^{\mathrm{th}}$') 484 string = string.replace('1th', '1$^{\mathrm{th}}$') 485 string = string.replace('2th', '2$^{\mathrm{th}}$') 486 string = string.replace('3th', '3$^{\mathrm{th}}$') 487 488 489 # Relaxation data. 490 ################## 491 492 # R1 and R2. 493 string = self.safe_replacement(string, 'R1', 'R$_1$') 494 string = self.safe_replacement(string, 'R2', 'R$_2$') 495 496 497 # Model-free parameters. 498 ######################## 499 500 # S2f, S2s, S2, te, ts, tf, tm, Rex, r. 501 string = self.safe_replacement(string, 'S2f', '$S^2_f$') 502 string = self.safe_replacement(string, 'S2s', '$S^2_s$') 503 string = self.safe_replacement(string, 'S2', '$S^2$') 504 string = self.safe_replacement(string, 'te', '$\\tau_e$') 505 string = self.safe_replacement(string, 'ts', '$\\tau_s$') 506 string = self.safe_replacement(string, 'tf', '$\\tau_f$') 507 string = self.safe_replacement(string, 'tm', '$\\tau_m$') 508 string = self.safe_replacement(string, 'Rex', '$R_{ex}$') 509 string = self.safe_replacement(string, 'r', '$r$') 510 string = self.safe_replacement(string, '<r>', '$<$$r$$>$') 511 512 513 # Spectral densities. 514 ##################### 515 516 # J(w), J(0), J(wX), J(wH). 517 string = string.replace('J(w)', '$J(\omega)$') 518 string = string.replace('J(0)', '$J(0)$') 519 string = string.replace('J(wX)', '$J(\omega_X)$') 520 string = string.replace('J(wH)', '$J(\omega_H)$') 521 522 523 # Diffusion tensor parameters. 524 ############################## 525 526 # Diso, Da, Dr, Dx, Dy, Dz, Dpar, Dper, Dratio. 527 string = self.safe_replacement(string, 'Diso', '$\Diff_{iso}$') 528 string = self.safe_replacement(string, 'Da', '$\Diff_a$') 529 string = self.safe_replacement(string, 'Dr', '$\Diff_r$') 530 string = self.safe_replacement(string, 'R', '$\mathfrak{R}$') 531 string = self.safe_replacement(string, 'Dx', '$\Diff_x$') 532 string = self.safe_replacement(string, 'Dy', '$\Diff_y$') 533 string = self.safe_replacement(string, 'Dz', '$\Diff_z$') 534 string = self.safe_replacement(string, 'Dpar', '$\Diff_\Par$') 535 string = self.safe_replacement(string, 'Dper', '$\Diff_\Per$') 536 string = self.safe_replacement(string, 'Dratio', '$\Diff_{ratio}$') 537 538 539 # Angles. 540 ######### 541 542 # alpha, beta, gamma, theta, phi. 543 string = self.safe_replacement(string, 'alpha', '$\\alpha$') 544 string = self.safe_replacement(string, 'beta', '$\\beta$') 545 string = self.safe_replacement(string, 'gamma', '$\\gamma$') 546 string = self.safe_replacement(string, 'theta', '$\\theta$') 547 string = self.safe_replacement(string, 'phi', '$\\phi$') 548 549 550 # Direction cosines. 551 #################### 552 553 # delta_x, delta_y, delta_z. 554 string = self.safe_replacement(string, 'dx', '$\\delta_x$') 555 string = self.safe_replacement(string, 'dy', '$\\delta_y$') 556 string = self.safe_replacement(string, 'dz', '$\\delta_z$') 557 558 559 # Indices. 560 ########## 561 562 # i, j, k, l, m, n, x, y, z, A, b, u. 563 string = self.safe_replacement(string, 'i', '$i$') 564 string = self.safe_replacement(string, 'j', '$j$') 565 string = self.safe_replacement(string, 'k', '$k$') 566 string = self.safe_replacement(string, 'l', '$l$') 567 string = self.safe_replacement(string, 'm', '$m$') 568 string = self.safe_replacement(string, 'n', '$n$') 569 string = self.safe_replacement(string, 'x', '$x$') 570 string = self.safe_replacement(string, 'y', '$y$') 571 string = self.safe_replacement(string, 'z', '$z$') 572 string = self.safe_replacement(string, 'b', '$b$') 573 string = self.safe_replacement(string, 'u', '$u$') 574 575 576 # Misc. 577 ####### 578 579 # tau. 580 string = self.safe_replacement(string, 'tau', '$\\tau$') 581 582 # Polak-Ribi\`ere. 583 string = self.safe_replacement(string, 'Polak-Ribiere', 'Polak-Ribi\`ere') 584 585 586 # Return the new text. 587 return string
588 589
590 - def latex_quotes(self, string):
591 """Function for changing the quotes for LaTeX processing.""" 592 593 # Initialise. 594 new_string = '' 595 in_quote = 0 596 597 # Loop over the characters. 598 for i in range(len(string)): 599 # Find the quote marks. 600 if search('\'', string[i]): 601 # Swap the opening ' with `. 602 if not in_quote and (i == 0 or not search('[a-z]', string[i-1])): 603 new_string = new_string + '`' 604 in_quote = 1 605 continue 606 607 # Just exited the quote 608 else: 609 in_quote = 0 610 611 # Append the character. 612 new_string = new_string + string[i] 613 614 return new_string
615 616
617 - def latex_special_chars(self, string):
618 """Function for handling LaTeX special characters.""" 619 620 # Damned backslashes. 621 string = string.replace('\\', 'This is a backslash to be replaced at the end of this functioN') 622 623 # List of special characters (prefix a backslash). 624 for char in "#$%&_{}": 625 string = string.replace(char, '\\'+char) 626 627 # Doubly special characters (prefix a backslash and postfix '{}'). 628 for char in "^~": 629 string = string.replace(char, '\\'+char+'{}') 630 631 # Damned backslashes! 632 string = string.replace('This is a backslash to be replaced at the end of this functioN', '$\\backslash$') 633 634 # Add a backslash to where it really should be. 635 string = string.replace('linebreak[0]', '\linebreak[0]') 636 637 # Return the new text. 638 return string
639 640
641 - def quotes(self, index):
642 """Function for placing quotes within the quote environment.""" 643 644 # Split the word by '. 645 elements = self.words[index].split("'") 646 647 # Single word quote. 648 if len(elements) == 3: 649 self.words[index] = elements[0] + '\quotecmd{' + elements[1] + '}' + elements[2] 650 651 # Weird quote. 652 elif len(elements) > 3: 653 sys.stderr.write('Unknown quote: ' + repr(self.words[index])) 654 sys.exit() 655 656 # Multiword quote. 657 if len(elements) == 2: 658 # Start of the quote. 659 if not self.in_quote and not search('[a-z]$', elements[0]): 660 self.words[index] = elements[0] + '\quotecmd{' + elements[1] 661 self.in_quote = 1 662 663 # End of the quote. 664 elif self.in_quote: 665 self.words[index] = elements[0] + '}' + elements[1] 666 self.in_quote = 0
667 668
669 - def safe_replacement(self, string, text, latex):
670 """Only replace in safe places within the text.""" 671 672 # Combos (if only RE could be used!) 673 674 # A number out the front. 675 string = string.replace('0'+text, '0'+latex) 676 string = string.replace('1'+text, '1'+latex) 677 string = string.replace('2'+text, '2'+latex) 678 string = string.replace('3'+text, '3'+latex) 679 string = string.replace('4'+text, '4'+latex) 680 string = string.replace('5'+text, '5'+latex) 681 string = string.replace('6'+text, '6'+latex) 682 string = string.replace('7'+text, '7'+latex) 683 string = string.replace('8'+text, '8'+latex) 684 string = string.replace('9'+text, '9'+latex) 685 686 # In a sentence. 687 string = string.replace(' '+text+',', ' '+latex+',') 688 string = string.replace(' '+text+'.', ' '+latex+'.') 689 string = string.replace(' '+text+' ', ' '+latex+' ') 690 string = string.replace(' '+text+';', ' '+latex+';') 691 string = string.replace(' '+text+':', ' '+latex+':') 692 693 # In lists []. 694 string = string.replace('['+text+']', '['+latex+']') 695 string = string.replace('['+text+' ', '['+latex+' ') 696 string = string.replace('['+text+',', '['+latex+',') 697 string = string.replace('['+text+';', '['+latex+';') 698 string = string.replace(' '+text+']', ' '+latex+']') 699 700 # In lists (). 701 string = string.replace('('+text+')', '('+latex+')') 702 string = string.replace('('+text+' ', '('+latex+' ') 703 string = string.replace('('+text+',', '('+latex+',') 704 string = string.replace('('+text+';', '('+latex+';') 705 string = string.replace(' '+text+')', ' '+latex+')') 706 707 # In lists {}. 708 string = string.replace('{'+text+' ', '{'+latex+' ') 709 string = string.replace('{'+text+',', '{'+latex+',') 710 string = string.replace('{'+text+';', '{'+latex+';') 711 string = string.replace(' '+text+'\\', ' '+latex+'\\') 712 713 # Quoted. 714 string = string.replace('`'+text+'\'', '`'+latex+'\'') 715 string = string.replace('`'+text+' ', '`'+latex+' ') 716 string = string.replace('`'+text+',', '`'+latex+',') 717 string = string.replace('`'+text+'.', '`'+latex+'.') 718 string = string.replace('`'+text+';', '`'+latex+';') 719 string = string.replace(' '+text+'\'', ' '+latex+'\'') 720 721 # End of the line. 722 substring = string[-len(text)-1:].replace(' '+text, ' '+latex) 723 string = string[0:-len(text)-1] + substring 724 725 substring = string[-len(text)-1:].replace('.'+text, '.'+latex) 726 string = string[0:-len(text)-1] + substring 727 728 string = string.replace(' '+text+'\n', ' '+latex+'\n') 729 string = string.replace('.'+text+'\n', '.'+latex+'\n') 730 731 # Maths 732 string = string.replace(' '+text+'\^', ' '+latex+'\^') 733 string = string.replace('('+text+'\^', '('+latex+'\^') 734 string = string.replace('\n'+text+'\^', '\n'+latex+'\^') 735 736 # At the start of the line. 737 if search('^'+text+'['+punctuation+']', string) or search('^'+text+'['+whitespace+']', string) or search('\n'+text+'['+punctuation+']', string) or search('\n'+text+'['+whitespace+']', string): 738 string = string.replace(text+' ', latex+' ') 739 string = string.replace(text+',', latex+',') 740 string = string.replace(text+'.', latex+'.') 741 string = string.replace(text+';', latex+';') 742 string = string.replace(text+']', latex+']') 743 string = string.replace(text+')', latex+')') 744 string = string.replace(text+'^', latex+'^') 745 string = string.replace(text+'\\', latex+'\\') 746 string = string.replace(text+'\'', latex+'\'') 747 string = string.replace(text+'\n', latex+'\n') 748 749 750 # Return the string. 751 return string
752 753
754 - def script_definitions(self, uf_names):
755 """Create a LaTeX file defining the relax language syntax for the listings package. 756 757 @param uf_names: The list of all user function names. 758 @type uf_names: list of str 759 """ 760 761 # Open the file. 762 file = open(self.path + sep + 'script_definition.tex', 'w') 763 764 # Python keywords. 765 py_keywords = [ 766 'and', 767 'assert', 768 'break', 769 'continue', 770 'del', 771 'else', 772 'exec', 773 'global', 774 'help', 775 'if', 776 'in', 777 'is', 778 'for', 779 'not', 780 'or', 781 'pass', 782 'print', 783 'raise', 784 'return', 785 'while', 786 'yield' 787 ] 788 py_keywords2 = [ 789 'as', 790 'from', 791 'import', 792 ] 793 py_keywords3 = [ 794 'class', 795 'def', 796 ] 797 798 # Loop over the relax definitions. 799 for lang in ['relax', 'relax_log']: 800 # The relax language. 801 file.write("\lstdefinelanguage{%s}{\n" % lang) 802 803 # Allow the user function '.' character to be part of the keywords. 804 file.write(" alsoletter={.>|},\n") 805 806 # Output the first set of Python keywords. 807 if lang == 'relax': 808 file.write(" morekeywords={") 809 for name in py_keywords: 810 file.write("%s," % name) 811 file.write("},\n") 812 813 # Output the second set of Python keywords. 814 if lang == 'relax': 815 file.write(" morekeywords=[2]{") 816 for name in py_keywords2: 817 file.write("%s," % name) 818 file.write("},\n") 819 820 # Output the third set of Python keywords. 821 if lang == 'relax': 822 file.write(" morekeywords=[3]{") 823 for name in py_keywords3: 824 file.write("%s," % name) 825 file.write("},\n") 826 827 # Output the relax prompt. 828 file.write(" morekeywords=[4]{relax>,relax|},\n") 829 830 # Output the relax user functions as keywords. 831 file.write(" morekeywords=[5]{") 832 for name in uf_names: 833 file.write("%s," % name) 834 file.write("},\n") 835 836 # The rest of the definition. 837 file.write(" moreprocnamekeys={def,class},\n") 838 file.write(" sensitive=true,\n") 839 file.write(" morecomment=[l]{\#},\n") 840 file.write(" morestring=[b]',\n") 841 file.write(" morestring=[b]\",\n") 842 file.write(" morestring=[b]\"\"\",\n") 843 file.write("}\n") 844 845 # Close the file. 846 file.close()
847 848
849 - def tabular_wrapping(self, table, max_char=100):
850 """Determine if column wrapping should occur. 851 852 @param table: The table. 853 @type table: list of lists of str 854 @keyword max_char: The maximum number of characters a column is allowed before wrapping is applied. 855 @type max_char: int 856 @return: The list of flags for wrapping columns. 857 @rtype: list of bool 858 """ 859 860 # The column widths. 861 num_cols = len(table[0]) 862 widths = [0] * num_cols 863 for i in range(len(table)): 864 for j in range(num_cols): 865 # The element is larger than the previous. 866 if len(table[i][j]) > widths[j]: 867 widths[j] = len(table[i][j]) 868 869 # The wrapping. 870 wrap = [] 871 for i in range(len(widths)): 872 if widths[i] > max_char: 873 wrap.append(True) 874 else: 875 wrap.append(False) 876 877 # Return the result. 878 return wrap
879 880
881 - def word_formatting(self, text, bold=False):
882 """Format the text, word by word. 883 884 @param text: The text to format. 885 @type text: str 886 @keyword bold: A flag for the indexing which if True will cause index entries to be in bold font. 887 @type bold: bool 888 @return: The formatted text. 889 @rtype: str 890 """ 891 892 # Initialise. 893 new_text = '' 894 895 # Split the string. 896 self.words = text.split(' ') 897 898 # Loop over the words one by one. 899 for i in range(len(self.words)): 900 # Indexing. 901 self.indexing(i, bold=bold) 902 903 # Quotes. 904 self.quotes(i) 905 906 # Recreate the string. 907 if i == 0: 908 new_text = self.words[i] 909 else: 910 new_text += ' ' + self.words[i] 911 912 # Return the text. 913 return new_text
914 915
916 - def write_item_list(self, item_list):
917 """Format and write out an itemised list. 918 919 @param item_list: The list of items and description lists. 920 @type item_list: list of list of str 921 """ 922 923 # Loop over the elements. 924 latex_lines = [] 925 items = False 926 for i in range(len(item_list)): 927 # LaTeX formatting of the item. 928 item = item_list[i][0] 929 if item == None: 930 item = '' 931 if item != '': 932 items = True 933 item = self.latex_special_chars(item) 934 item = self.latex_formatting(item) 935 item = self.word_formatting(item) 936 937 # LaTeX formatting of the description. 938 desc = self.latex_special_chars(item_list[i][1]) 939 desc = self.latex_formatting(desc) 940 desc = self.word_formatting(desc) 941 942 # Write to file. 943 if item != '': 944 latex_lines.append(" \\item[%s --] %s\n" % (item, desc)) 945 else: 946 latex_lines.append(" \\item[]%s\n" % desc) 947 948 # Start the environment. 949 if not items: 950 self.file.write("\\begin{itemize}\n") 951 else: 952 self.file.write("\\begin{description}\n") 953 954 # Add the lines. 955 for line in latex_lines: 956 self.file.write(line) 957 958 # End the environment. 959 if not items: 960 self.file.write("\\end{itemize}\n\n") 961 else: 962 self.file.write("\\end{description}\n\n")
963 964
965 - def write_list(self, list):
966 """Format and write out a list. 967 968 @param list: The list. 969 @type list: list of str 970 """ 971 972 # Start the environment. 973 self.file.write("\\begin{itemize}\n") 974 975 # Loop over the elements. 976 for item in list: 977 # LaTeX formatting. 978 item = self.latex_special_chars(item) 979 item = self.latex_formatting(item) 980 item = self.word_formatting(item) 981 982 # Write to file. 983 self.file.write(" \\item[]%s\n" % item) 984 985 # End the environment. 986 self.file.write("\\end{itemize}\n\n")
987 988
989 - def write_paragraph(self, text):
990 """Format and write out the paragraph. 991 992 @param text: The single line of text to convert into a LaTeX paragraph. 993 @type text: str 994 """ 995 996 # LaTeX formatting. 997 text = self.latex_special_chars(text) 998 text = self.latex_formatting(text) 999 text = self.word_formatting(text) 1000 1001 # Write to file. 1002 self.file.write(text + "\n\n")
1003 1004
1005 - def write_prompt_example(self, list):
1006 """Format and write out the prompt UI examples. 1007 1008 @param list: The list of prompt UI examples. 1009 @type list: list of str 1010 """ 1011 1012 # Loop over the examples. 1013 for text in list: 1014 # Write to file. 1015 self.file.write("\\begin{lstlisting}[numbers=none]\n%s\n\\end{lstlisting}\n\n" % text) 1016 1017 # An extra newline. 1018 self.file.write("\n")
1019 1020
1021 - def write_table(self, label):
1022 """Format and write out a table. 1023 1024 @param label: The unique table label. 1025 @type label: list of lists of str 1026 """ 1027 1028 # Get the table. 1029 table = uf_tables.get_table(label) 1030 1031 # Add a reference. 1032 self.file.write("Please see Table~\\ref{%s} on page~\\pageref{%s}.\n\n" % (label, label)) 1033 1034 # The table already exists, so skip creating it a second time. 1035 if label in self.uf_table_labels: 1036 return 1037 else: 1038 self.uf_table_labels.append(label) 1039 1040 # Determine the table wrapping. 1041 col_wrap = self.tabular_wrapping(table.cells) 1042 wrap = sum(col_wrap) 1043 1044 # The number of rows and columns. 1045 num_rows = len(table.cells) 1046 num_cols = len(table.headings) 1047 1048 # Start the centred table. 1049 if table.longtable: 1050 # A longtable. 1051 self.file.write("\\onecolumn\n") 1052 self.file.write("\\begin{scriptsize}\n") 1053 self.file.write("\\begin{center}\n") 1054 self.file.write("\\begin{longtable}{%s}\n" % ("l"*num_cols)) 1055 else: 1056 # Normal tables. 1057 self.file.write("\\begin{table*}\n") 1058 self.file.write("\\begin{scriptsize}\n") 1059 self.file.write("\\begin{center}\n") 1060 1061 # A caption. 1062 self.file.write("\\caption[%s]{%s}\n" % (table.caption_short, table.caption)) 1063 1064 # The formatting. 1065 if table.longtable: 1066 # Start the longtable environment and add the toprule. 1067 self.file.write("\\\\\n") 1068 self.file.write("\\toprule\n") 1069 else: 1070 # Start the tabular environment and add the toprule. 1071 if wrap: 1072 self.file.write("\\begin{tabularx}{\\textwidth}{") 1073 else: 1074 self.file.write("\\begin{tabular}{") 1075 for i in range(num_cols): 1076 if col_wrap[i]: 1077 text = "X" 1078 else: 1079 text = "l" 1080 self.file.write(text) 1081 self.file.write("}\n") 1082 self.file.write("\\\\[-5pt]\n") 1083 self.file.write("\\toprule\n") 1084 1085 # Generate the LaTeX headings. 1086 for j in range(num_cols): 1087 # Column separator. 1088 if j > 0: 1089 self.file.write(' & ') 1090 1091 # The cell contents. 1092 cell = table.headings[j] 1093 cell = self.latex_special_chars(cell) 1094 cell = self.latex_formatting(cell) 1095 1096 # Write the cell contents. 1097 self.file.write(cell) 1098 1099 # End of the header line. 1100 self.file.write(" \\\\\n") 1101 1102 # The central formatting. 1103 if table.longtable: 1104 self.file.write("\\midrule\n") 1105 self.file.write("\\endhead\n\n") 1106 self.file.write("\\bottomrule\n") 1107 self.file.write("\\endfoot\n") 1108 else: 1109 # Add the midrule. 1110 self.file.write("\\midrule\n") 1111 1112 # The label for longtables. 1113 if table.longtable: 1114 self.file.write("\\label{%s}\n" % label) 1115 1116 # Loop over the main table lines. 1117 for i in range(num_rows): 1118 # Loop over the columns. 1119 for j in range(num_cols): 1120 # Column separator. 1121 if j > 0: 1122 self.file.write(' & ') 1123 1124 # The cell contents. 1125 cell = table.cells[i][j] 1126 cell = self.latex_special_chars(cell) 1127 cell = self.latex_formatting(cell) 1128 1129 # Write the cell contents. 1130 self.file.write(cell) 1131 1132 # End of the line. 1133 self.file.write(" \\\\\n") 1134 1135 # Terminate. 1136 if table.longtable: 1137 self.file.write("\\end{longtable}\n") 1138 self.file.write("\\end{center}\n") 1139 self.file.write("\\end{scriptsize}\n") 1140 self.file.write("\\twocolumn\n") 1141 else: 1142 self.file.write("\\bottomrule\n") 1143 self.file.write("\\\\[-5pt]\n") 1144 self.file.write("\\label{%s}\n" % label) 1145 if wrap: 1146 self.file.write("\\end{tabularx}\n") 1147 else: 1148 self.file.write("\\end{tabular}\n") 1149 self.file.write("\\end{center}\n") 1150 self.file.write("\\end{scriptsize}\n") 1151 self.file.write("\\end{table*}\n") 1152 1153 # Increment the table counts. 1154 self.table_count += 1 1155 self.uf_table_count += 1 1156 1157 # A some newlines. 1158 self.file.write("\n\n")
1159 1160
1161 - def write_verbatim(self, text):
1162 """Format and write out the verbatim text. 1163 1164 @param text: The text to write out in a LaTeX verbatim environment. 1165 @type text: str 1166 """ 1167 1168 # Write to file. 1169 self.file.write("{\\footnotesize \\begin{verbatim}\n") 1170 self.file.write(text) 1171 self.file.write("\n\\end{verbatim}}\n\n")
1172