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