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-2013 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 # The relax language. 799 file.write("\lstdefinelanguage{relax}{\n") 800 801 # Allow the user function '.' character to be part of the keywords. 802 file.write(" alsoletter={.>|},\n") 803 804 # Output the first set of Python keywords. 805 file.write(" morekeywords={") 806 for name in py_keywords: 807 file.write("%s," % name) 808 file.write("},\n") 809 810 # Output the second set of Python keywords. 811 file.write(" morekeywords=[2]{") 812 for name in py_keywords2: 813 file.write("%s," % name) 814 file.write("},\n") 815 816 # Output the third set of Python keywords. 817 file.write(" morekeywords=[3]{") 818 for name in py_keywords3: 819 file.write("%s," % name) 820 file.write("},\n") 821 822 # Output the relax prompt. 823 file.write(" morekeywords=[4]{relax>,relax|},\n") 824 825 # Output the relax user functions as keywords. 826 file.write(" morekeywords=[5]{") 827 for name in uf_names: 828 file.write("%s," % name) 829 file.write("},\n") 830 831 # The rest of the definition. 832 file.write(" moreprocnamekeys={def,class},\n") 833 file.write(" sensitive=true,\n") 834 file.write(" morecomment=[l]{\#},\n") 835 file.write(" morestring=[b]',\n") 836 file.write(" morestring=[b]\",\n") 837 file.write(" morestring=[b]\"\"\",\n") 838 file.write("}\n") 839 840 # Close the file. 841 file.close()
842 843
844 - def tabular_wrapping(self, table, max_char=100):
845 """Determine if column wrapping should occur. 846 847 @param table: The table. 848 @type table: list of lists of str 849 @keyword max_char: The maximum number of characters a column is allowed before wrapping is applied. 850 @type max_char: int 851 @return: The list of flags for wrapping columns. 852 @rtype: list of bool 853 """ 854 855 # The column widths. 856 num_cols = len(table[0]) 857 widths = [0] * num_cols 858 for i in range(len(table)): 859 for j in range(num_cols): 860 # The element is larger than the previous. 861 if len(table[i][j]) > widths[j]: 862 widths[j] = len(table[i][j]) 863 864 # The wrapping. 865 wrap = [] 866 for i in range(len(widths)): 867 if widths[i] > max_char: 868 wrap.append(True) 869 else: 870 wrap.append(False) 871 872 # Return the result. 873 return wrap
874 875
876 - def word_formatting(self, text, bold=False):
877 """Format the text, word by word. 878 879 @param text: The text to format. 880 @type text: str 881 @keyword bold: A flag for the indexing which if True will cause index entries to be in bold font. 882 @type bold: bool 883 @return: The formatted text. 884 @rtype: str 885 """ 886 887 # Initialise. 888 new_text = '' 889 890 # Split the string. 891 self.words = text.split(' ') 892 893 # Loop over the words one by one. 894 for i in range(len(self.words)): 895 # Indexing. 896 self.indexing(i, bold=bold) 897 898 # Quotes. 899 self.quotes(i) 900 901 # Recreate the string. 902 if i == 0: 903 new_text = self.words[i] 904 else: 905 new_text += ' ' + self.words[i] 906 907 # Return the text. 908 return new_text
909 910
911 - def write_item_list(self, item_list):
912 """Format and write out an itemised list. 913 914 @param item_list: The list of items and description lists. 915 @type item_list: list of list of str 916 """ 917 918 # Loop over the elements. 919 latex_lines = [] 920 items = False 921 for i in range(len(item_list)): 922 # LaTeX formatting of the item. 923 item = item_list[i][0] 924 if item == None: 925 item = '' 926 if item != '': 927 items = True 928 item = self.latex_special_chars(item) 929 item = self.latex_formatting(item) 930 item = self.word_formatting(item) 931 932 # LaTeX formatting of the description. 933 desc = self.latex_special_chars(item_list[i][1]) 934 desc = self.latex_formatting(desc) 935 desc = self.word_formatting(desc) 936 937 # Write to file. 938 if item != '': 939 latex_lines.append("\\item[%s --] %s\n" % (item, desc)) 940 else: 941 latex_lines.append("\\item[]%s\n" % desc) 942 943 # Start the environment. 944 if not items: 945 self.file.write("\\begin{itemize}\n") 946 else: 947 self.file.write("\\begin{description}\n") 948 949 # Add the lines. 950 for line in latex_lines: 951 self.file.write(line) 952 953 # End the environment. 954 if not items: 955 self.file.write("\\end{itemize}\n\n") 956 else: 957 self.file.write("\\end{description}\n\n")
958 959
960 - def write_list(self, list):
961 """Format and write out a list. 962 963 @param list: The list. 964 @type list: list of str 965 """ 966 967 # Start the environment. 968 self.file.write("\\begin{itemize}\n") 969 970 # Loop over the elements. 971 for item in list: 972 # LaTeX formatting. 973 item = self.latex_special_chars(item) 974 item = self.latex_formatting(item) 975 item = self.word_formatting(item) 976 977 # Write to file. 978 self.file.write("\\item[]%s\n" % item) 979 980 # End the environment. 981 self.file.write("\\end{itemize}\n\n")
982 983
984 - def write_paragraph(self, text):
985 """Format and write out the paragraph. 986 987 @param text: The single line of text to convert into a LaTeX paragraph. 988 @type text: str 989 """ 990 991 # LaTeX formatting. 992 text = self.latex_special_chars(text) 993 text = self.latex_formatting(text) 994 text = self.word_formatting(text) 995 996 # Write to file. 997 self.file.write(text + "\n\n")
998 999
1000 - def write_prompt_example(self, list):
1001 """Format and write out the prompt UI examples. 1002 1003 @param list: The list of prompt UI examples. 1004 @type list: list of str 1005 """ 1006 1007 # Loop over the examples. 1008 for text in list: 1009 # Write to file. 1010 self.file.write("\\begin{lstlisting}[numbers=none]\n%s\n\\end{lstlisting}\n\n" % text) 1011 1012 # An extra newline. 1013 self.file.write("\n")
1014 1015
1016 - def write_table(self, label):
1017 """Format and write out a table. 1018 1019 @param label: The unique table label. 1020 @type label: list of lists of str 1021 """ 1022 1023 # Get the table. 1024 table = uf_tables.get_table(label) 1025 1026 # Add a reference. 1027 self.file.write("Please see Table~\\ref{%s} on page~\\pageref{%s}.\n\n" % (label, label)) 1028 1029 # The table already exists, so skip creating it a second time. 1030 if label in self.uf_table_labels: 1031 return 1032 else: 1033 self.uf_table_labels.append(label) 1034 1035 # Determine the table wrapping. 1036 col_wrap = self.tabular_wrapping(table.cells) 1037 wrap = sum(col_wrap) 1038 1039 # The number of rows and columns. 1040 num_rows = len(table.cells) 1041 num_cols = len(table.headings) 1042 1043 # Start the centred table. 1044 if table.longtable: 1045 # A longtable. 1046 self.file.write("\\onecolumn\n") 1047 self.file.write("\\begin{scriptsize}\n") 1048 self.file.write("\\begin{center}\n") 1049 self.file.write("\\begin{longtable}{%s}\n" % ("l"*num_cols)) 1050 else: 1051 # Normal tables. 1052 self.file.write("\\begin{table*}\n") 1053 self.file.write("\\begin{scriptsize}\n") 1054 self.file.write("\\begin{center}\n") 1055 1056 # A caption. 1057 self.file.write("\\caption[%s]{%s}\n" % (table.caption_short, table.caption)) 1058 1059 # The formatting. 1060 if table.longtable: 1061 # Start the longtable environment and add the toprule. 1062 self.file.write("\\\\\n") 1063 self.file.write("\\toprule\n") 1064 else: 1065 # Start the tabular environment and add the toprule. 1066 if wrap: 1067 self.file.write("\\begin{tabularx}{\\textwidth}{") 1068 else: 1069 self.file.write("\\begin{tabular}{") 1070 for i in range(num_cols): 1071 if col_wrap[i]: 1072 text = "X" 1073 else: 1074 text = "l" 1075 self.file.write(text) 1076 self.file.write("}\n") 1077 self.file.write("\\\\[-5pt]\n") 1078 self.file.write("\\toprule\n") 1079 1080 # Generate the LaTeX headings. 1081 for j in range(num_cols): 1082 # Column separator. 1083 if j > 0: 1084 self.file.write(' & ') 1085 1086 # The cell contents. 1087 cell = table.headings[j] 1088 cell = self.latex_special_chars(cell) 1089 cell = self.latex_formatting(cell) 1090 1091 # Write the cell contents. 1092 self.file.write(cell) 1093 1094 # End of the header line. 1095 self.file.write(" \\\\\n") 1096 1097 # The central formatting. 1098 if table.longtable: 1099 self.file.write("\\midrule\n") 1100 self.file.write("\\endhead\n\n") 1101 self.file.write("\\bottomrule\n") 1102 self.file.write("\\endfoot\n") 1103 else: 1104 # Add the midrule. 1105 self.file.write("\\midrule\n") 1106 1107 # The label for longtables. 1108 if table.longtable: 1109 self.file.write("\\label{%s}\n" % label) 1110 1111 # Loop over the main table lines. 1112 for i in range(num_rows): 1113 # Loop over the columns. 1114 for j in range(num_cols): 1115 # Column separator. 1116 if j > 0: 1117 self.file.write(' & ') 1118 1119 # The cell contents. 1120 cell = table.cells[i][j] 1121 cell = self.latex_special_chars(cell) 1122 cell = self.latex_formatting(cell) 1123 1124 # Write the cell contents. 1125 self.file.write(cell) 1126 1127 # End of the line. 1128 self.file.write(" \\\\\n") 1129 1130 # Terminate. 1131 if table.longtable: 1132 self.file.write("\\end{longtable}\n") 1133 self.file.write("\\end{center}\n") 1134 self.file.write("\\end{scriptsize}\n") 1135 self.file.write("\\twocolumn\n") 1136 else: 1137 self.file.write("\\bottomrule\n") 1138 self.file.write("\\\\[-5pt]\n") 1139 self.file.write("\\label{%s}\n" % label) 1140 if wrap: 1141 self.file.write("\\end{tabularx}\n") 1142 else: 1143 self.file.write("\\end{tabular}\n") 1144 self.file.write("\\end{center}\n") 1145 self.file.write("\\end{scriptsize}\n") 1146 self.file.write("\\end{table*}\n") 1147 1148 # Increment the table counts. 1149 self.table_count += 1 1150 self.uf_table_count += 1 1151 1152 # A some newlines. 1153 self.file.write("\n\n")
1154 1155
1156 - def write_verbatim(self, text):
1157 """Format and write out the verbatim text. 1158 1159 @param text: The text to write out in a LaTeX verbatim environment. 1160 @type text: str 1161 """ 1162 1163 # Write to file. 1164 self.file.write("{\\footnotesize \\begin{verbatim}\n") 1165 self.file.write(text) 1166 self.file.write("\n\\end{verbatim}}\n\n")
1167