texdown
changeset 25:fb623913bfb4 tip
Moved lost of localmacros into texdown2latex and the rest into macros. The only stuff in localmacros now is stuff that is really report-specific, i.e. Apkudo-testing-report stuff for Apkudo testing reports.
| author | Nicholas FitzRoy-Dale (on multihonk2) <nicholas@fitzroydale.org> |
|---|---|
| date | Mon, 28 Nov 2011 18:01:53 +0000 |
| parents | 6b09b796daaa |
| children | |
| files | localmacros.py macros.py texdown2latex.py |
| diffstat | 3 files changed, 439 insertions(+), 362 deletions(-) [+] |
line diff
1.1 --- a/localmacros.py Wed Feb 09 17:59:54 2011 +0000 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,346 +0,0 @@ 1.4 -import re 1.5 - 1.6 -AFFILIATIONS = { 1.7 - 'NICTAUNSWThanks': r"""NICTA\thanks{ 1.8 - NICTA is funded by the Australian Government as represented by the 1.9 - Department of Broadband, Communications and the Digital Economy 1.10 - and the Australian Research Council through the ICT Centre of 1.11 - Excellence program. 1.12 - } and The University of New South Wales\\ 1.13 - Sydney, Australia""", 1.14 - 'GEN_AFFIL': r"""Insert Affiliation Here\\ 1.15 - City, Country""", 1.16 -} 1.17 - 1.18 -SIGPLANPAPER = r"""\documentclass[preprint,natbib,10pt]{sigplanconf} 1.19 - 1.20 -\usepackage{graphicx} 1.21 -\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth} 1.22 -\usepackage{url} 1.23 -\usepackage{amsmath} 1.24 -\usepackage[pdfborder={0 0 0}]{hyperref} 1.25 - 1.26 -\makeatletter 1.27 -\g@addto@macro\@verbatim\small 1.28 -\makeatother 1.29 - 1.30 -\begin{document} 1.31 - \conferenceinfo{%(conference0)s}{%(conference1)s} 1.32 - \copyrightyear{%(copyrightyear0)s} 1.33 - \title{%(title0)s} 1.34 - 1.35 - %(AUTHORS)s 1.36 - \maketitle 1.37 -""" 1.38 - 1.39 -TECHREPORT = r"""\documentclass[preprint,natbib,10pt]{article} 1.40 - 1.41 -\usepackage{graphicx} 1.42 -\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth} 1.43 -\usepackage{url} 1.44 -\usepackage{amsmath} 1.45 -\usepackage[pdfborder={0 0 0}]{hyperref} 1.46 - 1.47 -\makeatletter 1.48 -\g@addto@macro\@verbatim\small 1.49 -\makeatother 1.50 - 1.51 -\begin{document} 1.52 - \title{%(title0)s} 1.53 - 1.54 - %(AUTHORS)s 1.55 - \maketitle 1.56 -""" 1.57 - 1.58 -NICTATR = r"""\documentclass[preprint,natbib,10pt]{article} 1.59 - 1.60 -\usepackage{graphicx} 1.61 -\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth} 1.62 -\usepackage{url} 1.63 -\usepackage{amsmath} 1.64 -\usepackage[pdfborder={0 0 0}]{hyperref} 1.65 - 1.66 -\makeatletter 1.67 -\g@addto@macro\@verbatim\small 1.68 -\makeatother 1.69 - 1.70 -\begin{document} 1.71 - \title{%(title0)s} 1.72 - 1.73 - %(AUTHORS)s 1.74 - \maketitle 1.75 -""" 1.76 - 1.77 -END_DOCUMENT=r""" 1.78 - \bibliographystyle{plainnat} 1.79 - \bibliography{papers} 1.80 - \end{document} 1.81 -""" 1.82 - 1.83 -END_DOCUMENT_PLAIN=r""" 1.84 - \bibliographystyle{plain} 1.85 - \bibliography{papers} 1.86 - \end{document} 1.87 -""" 1.88 - 1.89 -END_DOCUMENT_NIL = '' 1.90 - 1.91 - 1.92 -def separate_tabs(line): 1.93 - return re.split(r'\t+', line) 1.94 - 1.95 -def make_author(name, email, affiliation): 1.96 - all_info = [name] 1.97 - if email: 1.98 - all_info.append(r"\\" + "\n\t\t%s" % (email)) 1.99 - if affiliation: 1.100 - all_info.append(r"\\" + "\n\t\t%s" % (affiliation)) 1.101 - return r" \authorinfo{%s}" % (''.join(all_info))+ "\n" 1.102 - 1.103 -def make_author_plain(name, email, affiliation): 1.104 - all_info = [name] 1.105 - if email: 1.106 - all_info.append(r"\\" + "\n\t\t%s" % (email)) 1.107 - if affiliation: 1.108 - all_info.append(r"\\" + "\n\t\t%s" % (affiliation)) 1.109 - return r" \author{%s}" % (''.join(all_info))+ "\n" 1.110 - 1.111 -class Macros(object): 1.112 - def __init__(self, convert_cmd = None): 1.113 - self.end_document = END_DOCUMENT_NIL 1.114 - self.convert_cmd = convert_cmd 1.115 - self.page_width_mm = 210 - 89 # subtract margins 1.116 - 1.117 - def macro_sigplanpaper(self, block_lines): 1.118 - self.end_document = END_DOCUMENT_PLAIN 1.119 - self.author = make_author 1.120 - return SIGPLANPAPER % self.anypaper(block_lines) 1.121 - 1.122 - def macro_techreport(self, block_lines): 1.123 - self.end_document = END_DOCUMENT_PLAIN 1.124 - self.author = make_author_plain 1.125 - return TECHREPORT % self.anypaper(block_lines) 1.126 - 1.127 - def macro_nictatr(self, block_lines): 1.128 - self.end_document = END_DOCUMENT_PLAIN 1.129 - self.author = make_author_plain 1.130 - return NICTATR % self.anypaper(block_lines) 1.131 - 1.132 - def anypaper(self, block_lines): 1.133 - info = {'AUTHORS': '?authors', 1.134 - 'conference': ('?conf', '?conf'), 1.135 - 'copyrightyear': '?year', 1.136 - 'title': '?title'} 1.137 - 1.138 - authors = [] 1.139 - 1.140 - for line in block_lines: 1.141 - line = separate_tabs(line) 1.142 - key = line.pop(0) 1.143 - 1.144 - if key == 'author': 1.145 - author_name = line[0] 1.146 - if len(line) >= 2: 1.147 - author_email = line[1] 1.148 - else: 1.149 - author_email = None 1.150 - if len(line) >= 3: 1.151 - if line[2].startswith('"'): 1.152 - # Directly-written affiliation 1.153 - assert line[2].endswith('"') 1.154 - author_affil = line[2][1:-1] 1.155 - else: 1.156 - author_affil = AFFILIATIONS[line[2]] 1.157 - else: 1.158 - author_affil = None 1.159 - authors.append(self.author(author_name, author_email, author_affil)) 1.160 - else: 1.161 - for idx in range(len(line)): 1.162 - info[key + str(idx)] = line[idx] 1.163 - 1.164 - if authors: 1.165 - info['AUTHORS'] = '\n'.join(authors) 1.166 - return info 1.167 - 1.168 - def fancy_table(self, block_lines, check_for_sizes = False, 1.169 - make_float = True): 1.170 - """ 1.171 - Produces a table containing data. Numbers must be tab separated. EG: 1.172 - X Y !!numericresults 1.173 - 37 1 1.174 - 38 2 1.175 - """ 1.176 - 1.177 - if block_lines[-1].startswith('~~'): 1.178 - caption = block_lines.pop() 1.179 - else: 1.180 - caption = None 1.181 - result = [] 1.182 - if make_float: 1.183 - result.append('\\begin{table}\n') 1.184 - 1.185 - block_lines = [separate_tabs(line) for line in block_lines] 1.186 - cols = len(block_lines[0]) 1.187 - 1.188 - latex_sizes = ['l'] * cols # The default 1.189 - 1.190 - if check_for_sizes: 1.191 - # The first row may contain size information of the form !\d+%. If 1.192 - # it does, use 'p' rather than 'l' to lay out the table, and base 1.193 - # the overall size on the known page width. 1.194 - all_sizes_percent = [-1] * cols 1.195 - found_one = False 1.196 - for col_num, element in enumerate(block_lines[0]): 1.197 - matcher = re.match(r'.*!([0-9]+)%$', element) 1.198 - if matcher: 1.199 - found_one = True 1.200 - all_sizes_percent[col_num] = int(matcher.group(1)) 1.201 - block_lines[0][col_num] = element[:element.rfind('!')] 1.202 - 1.203 - if found_one: 1.204 - # Assign any missing numbers 1.205 - perc_left = 100 1.206 - for col_num in range(cols): 1.207 - if all_sizes_percent[col_num] == -1: 1.208 - all_sizes_percent[col_num] = perc_left 1.209 - else: 1.210 - perc_left -= all_sizes_percent[col_num] 1.211 - 1.212 - # Convert to mm 1.213 - all_sizes_mm = [(self.page_width_mm * col_size) / 100 \ 1.214 - for col_size \ 1.215 - in all_sizes_percent] 1.216 - latex_sizes = ['p{%dmm}' % (size_mm) for size_mm in all_sizes_mm] 1.217 - 1.218 - # Check for magical alignment of columns. 1.219 - # Left-alignment (the default): cells neither start nor end with a space. 1.220 - # Right-alignment: At least one cell starts with a space; no cell ends with one. 1.221 - # Centered alignment: At least one cell both starts and ends with a space. 1.222 - # at least one entry with a space. 1.223 - for col_num in range(cols): 1.224 - align = latex_sizes[col_num] 1.225 - if len(align) == 1 and align in 'lcr': 1.226 - for line in block_lines: 1.227 - cell = line[col_num] 1.228 - if cell.startswith(' ') and align == 'l': 1.229 - align = 'r' 1.230 - if cell.endswith(' '): 1.231 - align = 'c' 1.232 - latex_sizes[col_num] = align 1.233 - 1.234 - latex_sizecmd = ''.join(latex_sizes) 1.235 - result.append(' \\begin{tabular}{%s}\n' % latex_sizecmd) 1.236 - 1.237 - count = 0 1.238 - for line in block_lines: 1.239 - elements = [self.convert_cmd(element) for element in line] 1.240 - result.append('\t' + ' & '.join(elements) + r'\\' + '\n') 1.241 - count += 1 1.242 - 1.243 - result.append(' \\end{tabular}\n') 1.244 - if caption: 1.245 - result.append(caption) 1.246 - if make_float: 1.247 - result.append('\\end{table}\n') 1.248 - return ''.join(result) 1.249 - 1.250 - def macro_numericresults(self, block_lines): 1.251 - return self.fancy_table(block_lines) 1.252 - 1.253 - def macro_floatgraphic(self, args): 1.254 - """ 1.255 - Includes a graphic, places it in a figure, and gives it a label. Usage: 1.256 - !!floatgraphic filename, Caption goes here 1.257 - """ 1.258 - if ',' in args: 1.259 - filename, caption = args.split(',', 1) 1.260 - caption = caption.strip() 1.261 - else: 1.262 - filename = args 1.263 - caption = None 1.264 - 1.265 - label = filename 1.266 - if '/' in label: 1.267 - label = label.split('/')[-1] 1.268 - if '#' in label: 1.269 - filename = filename.split('#')[0] 1.270 - label = label.replace('#', '.') 1.271 - label = label.replace('-', '.') 1.272 - 1.273 - result = [ 1.274 - '\\begin{figure}[htb]', 1.275 - ' \\begin{center}', 1.276 - ' \\includegraphics{figures/%s}' % (filename), 1.277 - ' \\end{center}', 1.278 - ' \\caption{\\label{figure.%s}%s}' % (label, caption), 1.279 - '\\end{figure}', 1.280 - ] 1.281 - 1.282 - return '\n'.join(result) 1.283 - 1.284 - def macro_floatgraphic_wholepage(self, args): 1.285 - result = [self.macro_floatgraphic(args), 1.286 - '\\afterpage{\\clearpage}'] 1.287 - return '\n'.join(result) 1.288 - 1.289 - 1.290 - def macro_absolutegraphic(self, args): 1.291 - """ 1.292 - Includes an absolutely-positioned graphic without label. 1.293 - """ 1.294 - filename, left, top, height= \ 1.295 - [arg.strip() for arg in args.split(',')] 1.296 - result = [ 1.297 - r'\begin{picture}(0.0, 0.0)', 1.298 - r' \put(%s,%s) {' % (left, top), 1.299 - r' \includegraphics[height=%s]{figures/%s}' % (height, filename), 1.300 - r' }', 1.301 - r'\end{picture}', 1.302 - ] 1.303 - return '\n'.join(result) 1.304 - 1.305 - def macro_floatcode(self, block_lines, placement_spec = None): 1.306 - """ 1.307 - Code inside a figure. If the final line is a caption, does the right 1.308 - thing. Usage: 1.309 - code line 1 !!floatcode 1.310 - final code line 1.311 - ~~ <<label.if.wanted>> Caption if wanted ~~ 1.312 - """ 1.313 - if placement_spec is None: 1.314 - placement_spec = 'htb' 1.315 - 1.316 - caption = None 1.317 - if block_lines[-1].startswith('~~'): 1.318 - caption = block_lines.pop() 1.319 - block_lines = [line.replace('\t', ' ') for line in block_lines] 1.320 - result = ['\\begin{figure}[%s]' % (placement_spec)] 1.321 - result.append('\\begin{verbatim}') 1.322 - result.extend(block_lines) 1.323 - result.append('\\end{verbatim}') 1.324 - if caption: 1.325 - result.append(caption) 1.326 - result.append('\\end{figure}') 1.327 - return '\n'.join(result) 1.328 - 1.329 - def macro_exactfloatcode(self, block_lines): 1.330 - return self.macro_floatcode(block_lines, 'h!') 1.331 - 1.332 - def macro_floattable(self, block_lines): 1.333 - return self.fancy_table(block_lines, check_for_sizes = True) 1.334 - 1.335 - def macro_inlinetable(self, block_lines): 1.336 - return self.fancy_table(block_lines, check_for_sizes = True, make_float = False) 1.337 - 1.338 - def macro_blockquote(self, block_lines): 1.339 - # Special-case attribution line. 1.340 - if block_lines[-1].startswith('--'): 1.341 - block_lines[-1] = r'\begin{flushright} --' +\ 1.342 - self.convert_cmd(block_lines[-1][2:]) +\ 1.343 - r'\end{flushright}' 1.344 - result = [r'\begin{quote}'] + block_lines + [r'\end{quote}'] 1.345 - return '\n'.join(result) + '\n' 1.346 - 1.347 - def macro_end_document(self, args): 1.348 - return self.end_document 1.349 -
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/macros.py Mon Nov 28 18:01:53 2011 +0000 2.3 @@ -0,0 +1,116 @@ 2.4 + 2.5 +AFFILIATIONS = { 2.6 + 'NICTAUNSWThanks': r"""NICTA\thanks{ 2.7 + NICTA is funded by the Australian Government as represented by the 2.8 + Department of Broadband, Communications and the Digital Economy 2.9 + and the Australian Research Council through the ICT Centre of 2.10 + Excellence program. 2.11 + } and The University of New South Wales\\ 2.12 + Sydney, Australia""", 2.13 + 'GEN_AFFIL': r"""Insert Affiliation Here\\ 2.14 + City, Country""", 2.15 +} 2.16 + 2.17 +SIGPLANPAPER = r"""\documentclass[preprint,natbib,10pt]{sigplanconf} 2.18 + 2.19 +\usepackage{graphicx} 2.20 +\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth} 2.21 +\usepackage{url} 2.22 +\usepackage{amsmath} 2.23 +\usepackage[pdfborder={0 0 0}]{hyperref} 2.24 + 2.25 +\makeatletter 2.26 +\g@addto@macro\@verbatim\small 2.27 +\makeatother 2.28 + 2.29 +\begin{document} 2.30 + \conferenceinfo{%(conference0)s}{%(conference1)s} 2.31 + \copyrightyear{%(copyrightyear0)s} 2.32 + \title{%(title0)s} 2.33 + 2.34 + %(AUTHORS)s 2.35 + \maketitle 2.36 +""" 2.37 + 2.38 +TECHREPORT = r"""\documentclass[preprint,natbib,10pt]{article} 2.39 + 2.40 +\usepackage{graphicx} 2.41 +\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth} 2.42 +\usepackage{url} 2.43 +\usepackage{amsmath} 2.44 +\usepackage[pdfborder={0 0 0}]{hyperref} 2.45 +\usepackage{caption} 2.46 + 2.47 +\makeatletter 2.48 +\g@addto@macro\@verbatim\small 2.49 +\makeatother 2.50 + 2.51 +\begin{document} 2.52 + \title{%(title0)s} 2.53 + 2.54 + %(AUTHORS)s 2.55 + \maketitle 2.56 +""" 2.57 + 2.58 +NICTATR = r"""\documentclass[preprint,natbib,10pt]{article} 2.59 + 2.60 +\usepackage{graphicx} 2.61 +\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth} 2.62 +\usepackage{url} 2.63 +\usepackage{amsmath} 2.64 +\usepackage[pdfborder={0 0 0}]{hyperref} 2.65 + 2.66 +\makeatletter 2.67 +\g@addto@macro\@verbatim\small 2.68 +\makeatother 2.69 + 2.70 +\begin{document} 2.71 + \title{%(title0)s} 2.72 + 2.73 + %(AUTHORS)s 2.74 + \maketitle 2.75 +""" 2.76 + 2.77 +END_DOCUMENT=r""" 2.78 + \bibliographystyle{plainnat} 2.79 + \bibliography{papers} 2.80 + \end{document} 2.81 +""" 2.82 + 2.83 +END_DOCUMENT_PLAIN=r""" 2.84 + \bibliographystyle{plain} 2.85 + \bibliography{papers} 2.86 + \end{document} 2.87 +""" 2.88 + 2.89 +END_DOCUMENT_NIL = '' 2.90 + 2.91 +class Macros(object): 2.92 + def __init__(self, texdown): 2.93 + self.texdown = texdown 2.94 + self.end_document = END_DOCUMENT_NIL 2.95 + 2.96 + def macro_sigplanpaper(self, block_lines): 2.97 + self.end_document = END_DOCUMENT_PLAIN 2.98 + self.author = self.texdown.make_author 2.99 + return SIGPLANPAPER % self.texdown.anypaper(block_lines) 2.100 + 2.101 + def macro_techreport(self, block_lines): 2.102 + self.end_document = END_DOCUMENT_PLAIN 2.103 + self.author = self.texdown.make_author_plain 2.104 + return TECHREPORT % self.texdown.anypaper(block_lines) 2.105 + 2.106 + def macro_acceptancetestingreport(self, block_lines): 2.107 + self.end_document = END_DOCUMENT_PLAIN 2.108 + self.author = self.texdown.make_author_plain 2.109 + return ACCEPTANCE_TESTING_REPORT % self.texdown.anypaper(block_lines) 2.110 + 2.111 + def macro_nictatr(self, block_lines): 2.112 + self.end_document = END_DOCUMENT_PLAIN 2.113 + self.author = self.texdown.make_author_plain 2.114 + return NICTATR % self.texdown.anypaper(block_lines) 2.115 + 2.116 + def macro_end_document(self, args): 2.117 + return self.end_document 2.118 + 2.119 +
3.1 --- a/texdown2latex.py Wed Feb 09 17:59:54 2011 +0000 3.2 +++ b/texdown2latex.py Mon Nov 28 18:01:53 2011 +0000 3.3 @@ -20,6 +20,7 @@ 3.4 """ 3.5 import re 3.6 import sys 3.7 +import macros as builtinmacros 3.8 # Attempt to import 'localmacros' from cwd preferentially. 3.9 sys.path.insert(0, '.') 3.10 import localmacros 3.11 @@ -56,19 +57,23 @@ 3.12 repl \\chapter*{\1} 3.13 incl label 3.14 chapter: 3.15 - match ^##(.*)## 3.16 + match ^## *(.*) *## 3.17 repl \\chapter{\1} 3.18 incl label 3.19 section: 3.20 - match ^==(.*)== 3.21 + match ^== *(.*) *== 3.22 repl \\section{\1} 3.23 incl label escape_underscores escape_percents teletype 3.24 +usenixabstract: 3.25 + match ^\^ *(.*) *\^ 3.26 + repl \\subsection*{\1} 3.27 + incl label escape_underscores escape_percents teletype 3.28 subsection: 3.29 - match ^=(.*)= 3.30 + match ^= *(.*) *= 3.31 repl \\subsection{\1} 3.32 incl label escape_underscores escape_percents teletype 3.33 subsubsection: 3.34 - match ^-(.*)- 3.35 + match ^- *(.*) *- 3.36 repl \\subsubsection{\1} 3.37 incl label escape_underscores escape_percents teletype 3.38 label: 3.39 @@ -146,7 +151,8 @@ 3.40 self.macros = {} 3.41 3.42 self.register_macros(self) 3.43 - self.register_macros(localmacros.Macros(self.convert)) 3.44 + self.register_macros(builtinmacros.Macros(self)) 3.45 + self.register_macros(localmacros.Macros(self)) 3.46 3.47 self.enum_depth = 0 # Keep track, so we can set the counter in \enumerate 3.48 3.49 @@ -157,13 +163,17 @@ 3.50 if key.startswith('macro_'): 3.51 self.macros[key[6:]] = getattr(obj, key) 3.52 3.53 - def convert(self, texdown, magic = False): 3.54 + def convert(self, texdown, magic = False, fragment = False): 3.55 """ 3.56 Conversion: 3.57 Text is list of (chunk, names of conversions for this chunk), 3.58 conceptually. Do a depth-first conversion and join up a 3.59 complete text block in reality. 3.60 """ 3.61 + if fragment: 3.62 + # Hack to ensure that ^ and $ don't match anything important. 3.63 + texdown = ' ' + texdown + ' ' 3.64 + 3.65 texdown = self.do_convert(texdown, CONVERSIONS_ORDER) 3.66 #for match, replacement in CONVERSIONS: 3.67 # texdown = self.convert_one(texdown, match, replacement) 3.68 @@ -173,14 +183,18 @@ 3.69 texdown += self.macros['end_document'](None) 3.70 3.71 # Hack: magical abstract conversion. 3.72 - abstract_start = texdown.find('\section{ Abstract }') 3.73 - if abstract_start != -1: 3.74 - abstract_end = texdown.find('\section', abstract_start + 1) 3.75 - texdown = texdown[:abstract_start] \ 3.76 - + '\\begin{abstract}\n' \ 3.77 - + texdown[abstract_start + 20: abstract_end] \ 3.78 - + '\\end{abstract}\n' \ 3.79 - + texdown[abstract_end:] 3.80 + if 0: 3.81 + abstract_start = texdown.find('\section{ Abstract }') 3.82 + if abstract_start != -1: 3.83 + abstract_end = texdown.find('\section', abstract_start + 1) 3.84 + texdown = texdown[:abstract_start] \ 3.85 + + '\\begin{abstract}\n' \ 3.86 + + texdown[abstract_start + 20: abstract_end] \ 3.87 + + '\\end{abstract}\n' \ 3.88 + + texdown[abstract_end:] 3.89 + 3.90 + if fragment: 3.91 + texdown = texdown[1:-1] 3.92 3.93 return texdown 3.94 3.95 @@ -194,7 +208,7 @@ 3.96 children = match_names[1:] 3.97 conv = CONVERSIONS[match_name] 3.98 3.99 - for pre_match, match in self.convert_one(text, conv): 3.100 + for pre_match, match in self.convert_one(text, match_name, conv): 3.101 if children: 3.102 pre_match = self.do_convert(pre_match, children) 3.103 if 'incl' in conv: 3.104 @@ -205,7 +219,7 @@ 3.105 return ''.join(result) 3.106 3.107 3.108 - def convert_one(self, texdown, conv): 3.109 + def convert_one(self, texdown, match_name, conv): 3.110 match = conv['match'] 3.111 3.112 matches = list(match.finditer(texdown)) 3.113 @@ -265,6 +279,11 @@ 3.114 else: 3.115 raise NotImplementedError() 3.116 3.117 + # If there is a post-processing handler, call it here. 3.118 + postprocess_handler = self.macros.get('postproc_%s' % (match_name)) 3.119 + if postprocess_handler: 3.120 + result = postprocess_handler(result) 3.121 + 3.122 yield before_match, result 3.123 3.124 if matches: 3.125 @@ -342,6 +361,294 @@ 3.126 except KeyError: 3.127 raise ConversionError("Macro '%s' not found." % (command)) 3.128 return handler(args) 3.129 + 3.130 + # Functions to make available to macros.py and localmacros.py. 3.131 + def separate_tabs(self, line): 3.132 + return re.split(r'\t+', line) 3.133 + 3.134 + def make_author(self, name, email, affiliation): 3.135 + all_info = [name] 3.136 + if email: 3.137 + all_info.append(r"\\" + "\n\t\t%s" % (email)) 3.138 + if affiliation: 3.139 + all_info.append(r"\\" + "\n\t\t%s" % (affiliation)) 3.140 + return r" \authorinfo{%s}" % (''.join(all_info))+ "\n" 3.141 + 3.142 + def make_author_plain(self, name, email, affiliation): 3.143 + all_info = [name] 3.144 + if email: 3.145 + all_info.append(r"\\" + "\n\t\t%s" % (email)) 3.146 + if affiliation: 3.147 + all_info.append(r"\\" + "\n\t\t%s" % (affiliation)) 3.148 + return r" \author{%s}" % (''.join(all_info))+ "\n" 3.149 + 3.150 + def anypaper(self, block_lines): 3.151 + info = {'AUTHORS': '?authors', 3.152 + 'conference': ('?conf', '?conf'), 3.153 + 'copyrightyear': '?year', 3.154 + 'title': '?title'} 3.155 + 3.156 + authors = [] 3.157 + 3.158 + for line in block_lines: 3.159 + line = self.texdown.separate_tabs(line) 3.160 + key = line.pop(0) 3.161 + 3.162 + if key == 'author': 3.163 + author_name = line[0] 3.164 + if len(line) >= 2: 3.165 + author_email = line[1] 3.166 + else: 3.167 + author_email = None 3.168 + if len(line) >= 3: 3.169 + if line[2].startswith('"'): 3.170 + # Directly-written affiliation 3.171 + assert line[2].endswith('"') 3.172 + author_affil = line[2][1:-1] 3.173 + else: 3.174 + author_affil = AFFILIATIONS[line[2]] 3.175 + else: 3.176 + author_affil = None 3.177 + authors.append(self.author(author_name, author_email, author_affil)) 3.178 + else: 3.179 + for idx in range(len(line)): 3.180 + info[key + str(idx)] = line[idx] 3.181 + 3.182 + if authors: 3.183 + info['AUTHORS'] = '\n'.join(authors) 3.184 + return info 3.185 + 3.186 + # Popular stuff from localmacros.py 3.187 + def fancy_table(self, block_lines, check_for_sizes = False, make_float = True, cell_func = None, horizborders = None, vertborders = None): 3.188 + """ 3.189 + Produces a table containing data. Numbers must be tab separated. EG: 3.190 + X Y !!numericresults 3.191 + 37 1 3.192 + 38 2 3.193 + """ 3.194 + 3.195 + if block_lines[-1].startswith('~~'): 3.196 + caption = block_lines.pop() 3.197 + else: 3.198 + caption = None 3.199 + result = [] 3.200 + if make_float: 3.201 + result.append('\\begin{table}\n') 3.202 + 3.203 + block_lines = [self.separate_tabs(line) for line in block_lines] 3.204 + cols = len(block_lines[0]) 3.205 + 3.206 + if cell_func: 3.207 + for rownum in range(len(block_lines)): 3.208 + line = block_lines[rownum] 3.209 + for colnum in range(len(line)): 3.210 + line[colnum] = cell_func(rownum, colnum, line[colnum]) 3.211 + block_lines[rownum] = line 3.212 + 3.213 + 3.214 + latex_sizes = ['l'] * cols # The default 3.215 + 3.216 + if check_for_sizes: 3.217 + # The first row may contain size information of the form !\d+%. If 3.218 + # it does, use 'p' rather than 'l' to lay out the table, and base 3.219 + # the overall size on the known page width. 3.220 + all_sizes_percent = [-1] * cols 3.221 + found_one = False 3.222 + for col_num, element in enumerate(block_lines[0]): 3.223 + matcher = re.match(r'.*!([0-9]+)%$', element) 3.224 + if matcher: 3.225 + found_one = True 3.226 + all_sizes_percent[col_num] = int(matcher.group(1)) 3.227 + block_lines[0][col_num] = element[:element.rfind('!')] 3.228 + 3.229 + if found_one: 3.230 + # Assign any missing numbers 3.231 + perc_left = 100 3.232 + for col_num in range(cols): 3.233 + if all_sizes_percent[col_num] == -1: 3.234 + all_sizes_percent[col_num] = perc_left 3.235 + else: 3.236 + perc_left -= all_sizes_percent[col_num] 3.237 + 3.238 + # Convert to mm 3.239 + all_sizes_mm = [(self.page_width_mm * col_size) / 100 \ 3.240 + for col_size \ 3.241 + in all_sizes_percent] 3.242 + latex_sizes = ['p{%dmm}' % (size_mm) for size_mm in all_sizes_mm] 3.243 + 3.244 + # Check for magical alignment of columns. 3.245 + # Left-alignment (the default): cells neither start nor end with a space. 3.246 + # Right-alignment: At least one cell starts with a space; no cell ends with one. 3.247 + # Centered alignment: At least one cell both starts and ends with a space. 3.248 + # at least one entry with a space. 3.249 + for col_num in range(cols): 3.250 + align = latex_sizes[col_num] 3.251 + if len(align) == 1 and align in 'lcr': 3.252 + for line in block_lines: 3.253 + cell = line[col_num] 3.254 + if cell.startswith(' ') and align == 'l': 3.255 + align = 'r' 3.256 + if cell.endswith(' '): 3.257 + align = 'c' 3.258 + latex_sizes[col_num] = align 3.259 + 3.260 + 3.261 + # Borders 3.262 + if horizborders: 3.263 + if horizborders[1] == '|': 3.264 + latex_sizes = [item for sublist in zip(latex_sizes, ['|'] * len(latex_sizes)) 3.265 + for item in sublist][:-1] 3.266 + if horizborders[0] == '|': 3.267 + latex_sizes.insert(0, '|') 3.268 + if horizborders[2] == '|': 3.269 + latex_sizes.append('|') 3.270 + 3.271 + # Start output 3.272 + latex_sizecmd = ''.join(latex_sizes) 3.273 + result.append(' \\begin{tabular}{%s}\n' % latex_sizecmd) 3.274 + 3.275 + 3.276 + if vertborders and vertborders[0] == '-': 3.277 + result.append('\\hline\n') 3.278 + 3.279 + count = 0 3.280 + for line in block_lines: 3.281 + if vertborders and vertborders[1] == '-' and count > 0: 3.282 + result.append('\\hline\n') 3.283 + if vertborders and vertborders[1] == 't' and count == 1: 3.284 + result.append('\\hline\n') 3.285 + elements = [self.convert(element) for element in line] 3.286 + 3.287 + result.append('\t') 3.288 + 3.289 + result.append(' & '.join(elements)) 3.290 + 3.291 + result.append(r'\\' + '\n') 3.292 + count += 1 3.293 + 3.294 + if vertborders and vertborders[2] == '-': 3.295 + result.append('\\hline\n') 3.296 + 3.297 + result.append(' \\end{tabular}\n') 3.298 + if caption: 3.299 + result.append(caption) 3.300 + if make_float: 3.301 + result.append('\\end{table}\n') 3.302 + return ''.join(result) 3.303 + 3.304 + def macro_floatgraphic(self, args): 3.305 + """ 3.306 + Includes a graphic, places it in a figure, and gives it a label. Usage: 3.307 + !!floatgraphic filename, Caption goes here 3.308 + """ 3.309 + return self.macro_anygraphic(args, floating = True) 3.310 + 3.311 + def macro_inlinegraphic(self, args): 3.312 + return self.macro_anygraphic(args, floating = False) 3.313 + 3.314 + def macro_anygraphic(self, args, floating = True, centered = False, floatspec = None, extra = ""): 3.315 + if ',' in args: 3.316 + filename, caption = args.split(',', 1) 3.317 + caption = caption.strip() 3.318 + else: 3.319 + filename = args 3.320 + caption = None 3.321 + 3.322 + label = filename 3.323 + if '/' in label: 3.324 + label = label.split('/')[-1] 3.325 + if '#' in label: 3.326 + filename = filename.split('#')[0] 3.327 + label = label.replace('#', '.') 3.328 + label = label.replace('-', '.') 3.329 + 3.330 + if floatspec is None: 3.331 + floatspec = '[htb]' 3.332 + 3.333 + result = [] 3.334 + 3.335 + if floating: 3.336 + result.append('\\begin{figure}%s' % (floatspec)) 3.337 + 3.338 + if centered: 3.339 + result.append('\\begin{center}') 3.340 + 3.341 + result.append('\\includegraphics%s{figures/%s}' % (extra, filename)) 3.342 + 3.343 + if centered: 3.344 + result.append(' \\end{center}') 3.345 + 3.346 + if floating: 3.347 + result.append(' \\caption{\\label{figure.%s}%s}' % (label, caption)) 3.348 + result.append('\\end{figure}') 3.349 + 3.350 + else: 3.351 + result.append('\\captionof{figure}{%s}' % (caption)) 3.352 + return '\n'.join(result) 3.353 + 3.354 + def macro_floatgraphic_wholepage(self, args): 3.355 + result = [self.macro_floatgraphic(args), 3.356 + '\\afterpage{\\clearpage}'] 3.357 + return '\n'.join(result) 3.358 + 3.359 + 3.360 + def macro_absolutegraphic(self, args): 3.361 + """ 3.362 + Includes an absolutely-positioned graphic without label. 3.363 + """ 3.364 + filename, left, top, height= \ 3.365 + [arg.strip() for arg in args.split(',')] 3.366 + result = [ 3.367 + r'\begin{picture}(0.0, 0.0)', 3.368 + r' \put(%s,%s) {' % (left, top), 3.369 + r' \includegraphics[height=%s]{figures/%s}' % (height, filename), 3.370 + r' }', 3.371 + r'\end{picture}', 3.372 + ] 3.373 + return '\n'.join(result) 3.374 + 3.375 + def macro_floatcode(self, block_lines, placement_spec = None): 3.376 + """ 3.377 + Code inside a figure. If the final line is a caption, does the right 3.378 + thing. Usage: 3.379 + code line 1 !!floatcode 3.380 + final code line 3.381 + ~~ <<label.if.wanted>> Caption if wanted ~~ 3.382 + """ 3.383 + if placement_spec is None: 3.384 + placement_spec = 'htb' 3.385 + 3.386 + caption = None 3.387 + if block_lines[-1].startswith('~~'): 3.388 + caption = block_lines.pop() 3.389 + block_lines = [line.replace('\t', ' ') for line in block_lines] 3.390 + result = ['\\begin{figure}[%s]' % (placement_spec)] 3.391 + result.append('\\begin{verbatim}') 3.392 + result.extend(block_lines) 3.393 + result.append('\\end{verbatim}') 3.394 + if caption: 3.395 + result.append(caption) 3.396 + result.append('\\end{figure}') 3.397 + return '\n'.join(result) 3.398 + 3.399 + def macro_exactfloatcode(self, block_lines): 3.400 + return self.macro_floatcode(block_lines, 'h!') 3.401 + 3.402 + def macro_floattable(self, block_lines): 3.403 + return self.fancy_table(block_lines, check_for_sizes = True) 3.404 + 3.405 + def macro_inlinetable(self, block_lines): 3.406 + return self.fancy_table(block_lines, check_for_sizes = True, make_float = False) 3.407 + 3.408 + def macro_blockquote(self, block_lines): 3.409 + # Special-case attribution line. 3.410 + if block_lines[-1].startswith('--'): 3.411 + block_lines[-1] = r'\begin{flushright} --' +\ 3.412 + self.convert(block_lines[-1][2:]) +\ 3.413 + r'\end{flushright}' 3.414 + result = [r'\begin{quote}'] + block_lines + [r'\end{quote}'] 3.415 + return '\n'.join(result) + '\n' 3.416 + 3.417 3.418 if __name__ == '__main__': 3.419 handle = codecs.open(sys.argv[1], 'r', encoding = 'utf-8')
