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