From 5cc46a7f675befcc6e18cacbaa6a9a3ffd78a9d9 Mon Sep 17 00:00:00 2001 From: Christophe Demko Date: Thu, 2 Jun 2016 16:00:09 +0200 Subject: [PATCH] Version 2.0.0 --- pandoc_numbering.py | 571 ++++++++++++++++++++++++++++++++------ setup.py | 2 +- tests/test_listings.py | 295 ++++++++++++++++++++ tests/test_numbering.py | 372 +++++++++++++++++++++++-- tests/test_referencing.py | 174 ++++++++++-- 5 files changed, 1271 insertions(+), 143 deletions(-) create mode 100644 tests/test_listings.py diff --git a/pandoc_numbering.py b/pandoc_numbering.py index 563f334..0010964 100644 --- a/pandoc_numbering.py +++ b/pandoc_numbering.py @@ -4,11 +4,11 @@ Pandoc filter to number all kinds of things. """ -from pandocfilters import toJSONFilters, walk, stringify, Str, Space, Para, Strong, Span, Link, Emph, RawInline +from pandocfilters import walk, stringify, Str, Space, Para, BulletList, Plain, Strong, Span, Link, Emph, RawInline, RawBlock, Header from functools import reduce -import sys import json import io +import sys import codecs import re import unicodedata @@ -16,9 +16,42 @@ count = {} information = {} +collections = {} headers = [0, 0, 0, 0, 0, 0] headerRegex = '(?P
(?P(-\.)*)(\+\.)*)' +def toJSONFilters(actions): + """Converts a list of actions into a filter that reads a JSON-formatted + pandoc document from stdin, transforms it by walking the tree + with the actions, and returns a new JSON-formatted pandoc document + to stdout. The argument is a list of functions action(key, value, format, meta), + where key is the type of the pandoc object (e.g. 'Str', 'Para'), + value is the contents of the object (e.g. a string for 'Str', + a list of inline elements for 'Para'), format is the target + output format (which will be taken for the first command line + argument if present), and meta is the document's metadata. + If the function returns None, the object to which it applies + will remain unchanged. If it returns an object, the object will + be replaced. If it returns a list, the list will be spliced in to + the list to which the target object belongs. (So, returning an + empty list deletes the object.) + """ + try: + input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') + except AttributeError: + # Python 2 does not have sys.stdin.buffer. + # REF: http://stackoverflow.com/questions/2467928/python-unicodeencodeerror-when-reading-from-stdin + input_stream = codecs.getreader("utf-8")(sys.stdin) + + doc = json.loads(input_stream.read()) + if len(sys.argv) > 1: + format = sys.argv[1] + else: + format = "" + altered = reduce(lambda x, action: walk(x, action, format, doc[0]['unMeta']), actions, doc) + addListings(altered, format, altered[0]['unMeta']) + json.dump(altered, sys.stdout) + def removeAccents(string): nfkd_form = unicodedata.normalize('NFKD', string) return u"".join([c for c in nfkd_form if not unicodedata.combining(c)]) @@ -32,6 +65,34 @@ def toIdentifier(string): return string +def toLatex(x): + """Walks the tree x and returns concatenated string content, + leaving out all formatting. + """ + result = [] + + def go(key, val, format, meta): + if key in ['Str', 'MetaString']: + result.append(val) + elif key == 'Code': + result.append(val[1]) + elif key == 'Math': + # Modified from the stringify function in the pandocfilter package + if format == 'latex': + result.append('$' + val[1] + '$') + else: + result.append(val[1]) + elif key == 'LineBreak': + result.append(" ") + elif key == 'Space': + result.append(" ") + elif key == 'Note': + # Do not stringify value from Note node + del val[:] + + walk(x, go, 'latex', {}) + return ''.join(result) + def numbering(key, value, format, meta): global headerRegex if key == 'Header': @@ -44,24 +105,29 @@ def numbering(key, value, format, meta): if len(value) >= 3 and value[-2] == Space() and value[-1]['t'] == 'Str': last = value[-1]['c'] - match = re.match('^' + headerRegex + '#(?P[a-zA-Z][\w.-]*:)?(?P[a-zA-Z][\w:.-]*)?$', last) + match = re.match('^' + headerRegex + '#((?P[a-zA-Z][\w.-]*):)?(?P[a-zA-Z][\w:.-]*)?$', last) if match: # Is it a Para and the last element is an identifier beginning with '#' - global count, information + global count, information, collections # Detect the title - title = None + title = [] if value[-3]['t'] == 'Str' and value[-3]['c'][-1:] == ')': for (i, item) in enumerate(value): if item['t'] == 'Str' and item['c'][0] == '(': - title = Emph(value[i:-2]) + title = value[i:-2] + title[0]['c'] = title[0]['c'][1:] + title[-1]['c'] = title[-1]['c'][:-1] value = value[:i - 1] + value[-2:] break + # Compute the description + description = value[:-2] + # Compute the basicCategory and the category if match.group('prefix') == None: - basicCategory = toIdentifier(stringify(value[:-2])) + ':' + basicCategory = toIdentifier(stringify(description)) else: basicCategory = match.group('prefix') @@ -71,15 +137,18 @@ def numbering(key, value, format, meta): # Get the default inf and sup level if levelInf == 0 and levelSup == 0: - [levelInf, levelSup] = getDefaultLevels(basicCategory[:-1], meta) + [levelInf, levelSup] = getDefaultLevels(basicCategory, meta) + + # Compute the section number + sectionNumber = '.'.join(map(str, headers[:levelSup])) - # Compute the leading (composed of the section numbering) + # Compute the leading (composed of the section numbering and a dot) if levelSup != 0: - leading = '.'.join(map(str, headers[:levelSup])) + '.' + leading = sectionNumber + '.' else: leading = '' - category = basicCategory + leading + category = basicCategory + ':' + leading # Is it a new category? if category not in count: @@ -94,28 +163,84 @@ def numbering(key, value, format, meta): if match.group('name') == None: tag = category + number else: - tag = basicCategory + match.group('name') + tag = basicCategory + ':' + match.group('name') # Replace the '-.-.+.+...#' by the category count (omitting the hidden part) - value[-1]['c'] = '.'.join(map(str, headers[levelInf:levelSup] + [number])) + localNumber = '.'.join(map(str, headers[levelInf:levelSup] + [number])) - # Prepare the final text - text = [Strong(value)] + # Compute the globalNumber + if sectionNumber: + globalNumber = sectionNumber + '.' + number + else: + globalNumber = number + + # Is the automatic formatting required for this category? + if getFormat(basicCategory, meta): + # Prepare the final text + text = [Strong(description + [Space(), Str(localNumber)])] + + # Add the title to the final text + if title: + text = text + [Space(), Emph([Str('(')] + title + [Str(')')])] + + # Compute the link + link = description + [Space(), Str(localNumber)] + + # Compute the toc + toc = [Str(globalNumber), Space()] + if title: + toc = toc + title + else: + toc = toc + description + + else: + # Prepare the final text + text = [ + Span(['', ['description'], []], description), + Span(['', ['title'], []], title), + Span(['', ['local'], []], [Str(localNumber)]), + Span(['', ['global'], []], [Str(globalNumber)]), + Span(['', ['section'], []], [Str(sectionNumber)]), + ] + + # Compute the link + link = [Span(['', ['pandoc-numbering-link'] + getClasses(basicCategory, meta), []], text)] + + # Compute the toc + toc = [Span(['', ['pandoc-numbering-toc'] + getClasses(basicCategory, meta), []], text)] - # Add the title to the final text - if title != None: - text.append(Space()) - text.append(title) # Store the numbers and the label for automatic numbering (See referencing function) - information[tag] = {'number': value[-1]['c'], 'text': value} + information[tag] = { + 'section': sectionNumber, + 'local': localNumber, + 'global': globalNumber, + 'count': number, + 'description': description, + 'title': title, + 'link': link, + 'toc': toc + } # Prepare the contents - contents = [Span([tag, [], []], text)] + contents = [Span([tag, ['pandoc-numbering-text'] + getClasses(basicCategory, meta), []], text)] + + # Compute collections + if basicCategory not in collections: + collections[basicCategory] = [] + + collections[basicCategory].append(tag) # Special case for LaTeX - if format == 'latex': - contents.insert(0, RawInline('tex', '\\phantomsection')) + if format == 'latex' and getFormat(basicCategory, meta): + latexCategory = re.sub('[^a-z]+', '', basicCategory) + if title: + entry = title + else: + entry = description + latex = '\\phantomsection\\addcontentsline{' + latexCategory + '}{' + latexCategory + '}{\\protect\\numberline {' + \ + leading + number + '}{\ignorespaces ' + toLatex(entry) + '}}' + contents.insert(0, RawInline('tex', latex)) # Return the contents in a Para element return Para(contents) @@ -125,9 +250,14 @@ def numbering(key, value, format, meta): return Para(value) replace = None +search = None + +def lowering(key, value, format, meta): + if key == 'Str': + return Str(value.lower()) def referencing(key, value, format, meta): - global information, replace + global information, replace, search # Is it a link with a right reference? if key == 'Link': @@ -135,91 +265,356 @@ def referencing(key, value, format, meta): # pandoc 1.15 [text, [reference, title]] = value else: - # pandoc 1.16 + # pandoc > 1.15 [attributes, text, [reference, title]] = value - if re.match('^#([a-zA-Z][\w:.-]*)?$', reference): + if re.match('^(#([a-zA-Z][\w:.-]*))$', reference): # Compute the name tag = reference[1:] if tag in information: if pandocVersion() < '1.16': # pandoc 1.15 + i = 0 + else: + # pandoc > 1.15 + i = 1 + + # Replace all '#t', '#T', '#d', '#D', '#s', '#g', '#c', '#n', '#' with the corresponding text in the title + value[i + 1][1] = value[i + 1][1].replace('#t', stringify(information[tag]['title']).lower()) + value[i + 1][1] = value[i + 1][1].replace('#T', stringify(information[tag]['title'])) + value[i + 1][1] = value[i + 1][1].replace('#d', stringify(information[tag]['description']).lower()) + value[i + 1][1] = value[i + 1][1].replace('#D', stringify(information[tag]['description'])) + value[i + 1][1] = value[i + 1][1].replace('#s', information[tag]['section']) + value[i + 1][1] = value[i + 1][1].replace('#g', information[tag]['global']) + value[i + 1][1] = value[i + 1][1].replace('#c', information[tag]['count']) + value[i + 1][1] = value[i + 1][1].replace('#n', information[tag]['local']) + value[i + 1][1] = value[i + 1][1].replace('#', information[tag]['local']) + + if text == []: + # The link text is empty, replace it with the default label + value[i] = information[tag]['link'] + else: + # The link text is not empty + + #replace all '#t' with the title in lower case + replace = walk(information[tag]['title'], lowering, format, meta) + search = '#t' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#T' with the title + replace = information[tag]['title'] + search = '#T' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#d' with the description in lower case + replace = walk(information[tag]['description'], lowering, format, meta) + search = '#d' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#D' with the description + replace = information[tag]['description'] + search = '#D' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#s' with the corresponding number + replace = [Str(information[tag]['section'])] + search = '#s' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#g' with the corresponding number + replace = [Str(information[tag]['global'])] + search = '#g' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#c' with the corresponding number + replace = [Str(information[tag]['count'])] + search = '#c' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#n' with the corresponding number + replace = [Str(information[tag]['local'])] + search = '#n' + value[i] = walk(value[i], replacing, format, meta) + + #replace all '#' with the corresponding number + replace = [Str(information[tag]['local'])] + search = '#' + value[i] = walk(value[i], replacing, format, meta) - # Replace all '#' with the corresponding number in the title - value[1][1] = title.replace('#', information[tag]['number']) - if text == []: - # The link text is empty, replace it with the default label - value[0] = information[tag]['text'] - else: - # The link text is not empty, replace all '#' with the corresponding number - replace = information[tag]['number'] - value[0] = walk(text, replacing, format, meta) + elif key == 'Cite': + match = re.match('^(@(?P(?P[a-zA-Z][\w.-]*):(([a-zA-Z][\w.-]*)|(\d*(\.\d*)*))))$', value[1][0]['c']) + if match != None and getCiteShortCut(match.group('category'), meta): + + # Deal with @prefix:name shortcut + tag = match.group('tag') + if tag in information: + if pandocVersion() < '1.16': + # pandoc 1.15 + return Link([Str(information[tag]['local'])], ['#' + tag, '']) else: - # pandoc 1.16 + # pandoc > 1.15 + return Link(['', [], []], [Str(information[tag]['local'])], ['#' + tag, '']) + +def replacing(key, value, format, meta): + global replace, search + if key == 'Str': + prepare = value.split(search) + if len(prepare) > 1: + + ret = [] + + if prepare[0] != '': + ret.append(Str(prepare[0])) + + for string in prepare[1:]: + ret.extend(replace) + if string != '': + ret.append(Str(string)) + + return ret + +def addListings(doc, format, meta): + global collections, information + if 'pandoc-numbering' in meta and meta['pandoc-numbering']['t'] == 'MetaList': + + listings = [] + + # Loop on all listings definition + for definition in meta['pandoc-numbering']['c']: + if definition['t'] == 'MetaMap' and\ + 'category' in definition['c'] and\ + 'listing' in definition['c'] and\ + definition['c']['category']['t'] == 'MetaInlines' and\ + definition['c']['listing']['t'] == 'MetaInlines' and\ + len(definition['c']['category']['c']) == 1 and\ + definition['c']['category']['c'][0]['t'] == 'Str': - # Replace all '#' with the corresponding number in the title - value[2][1] = title.replace('#', information[tag]['number']) - if text == []: - # The link text is empty, replace it with the default label - value[1] = information[tag]['text'] + # Get the category name + category = definition['c']['category']['c'][0]['c'] + + # Get the title + title = definition['c']['listing']['c'] + + if format == 'latex': + + # Special case for latex output + + # Get the link color + if 'toccolor' in meta: + linkcolor = '\\hypersetup{linkcolor=' + stringify(meta['toccolor']['c']) + '}' else: - # The link text is not empty, replace all '#' with the corresponding number - replace = information[tag]['number'] - value[1] = walk(text, replacing, format, meta) - elif key == 'Cite': - if hasCiteShortCut(meta): - match = re.match('^@(?P[a-zA-Z][\w.-]*:(([a-zA-Z][\w.-]*)|(\d*(\.\d*)*)))$', value[1][0]['c']) - if match != None: - # Deal with @prefix:name shortcut - tag = match.group('tag') - if tag in information: - if pandocVersion() < '1.16': - return Link([Str(information[tag]['number'])], ['#' + tag, '']) + linkcolor = '\\hypersetup{linkcolor=black}' + + # Get the tab + if 'tab' in definition['c'] and definition['c']['tab']['t'] == 'MetaString': + try: + tab = float(definition['c']['tab']['c']) + except ValueError: + tab = None else: - return Link(['', [], []], [Str(information[tag]['number'])], ['#' + tag, '']) + tab = None + + # Get the space + if 'space' in definition['c'] and definition['c']['space']['t'] == 'MetaString': + try: + space = float(definition['c']['space']['c']) + except ValueError: + space = None + else: + space = None + + # Deal with default tab length + if tab == None: + tab = 1.5 + + # Deal with default space length + if space == None: + level = 0 + if category in collections: + # Loop on the collection + for tag in collections[category]: + level = max(level, information[tag]['section'].count('.')) + space = level + 2.3 + + # Add a RawBlock + latexCategory = re.sub('[^a-z]+', '', category) + latex = [ + linkcolor, + '\\makeatletter', + '\\newcommand*\\l@' + latexCategory + '{\\@dottedtocline{1}{' + str(tab) + 'em}{'+ str(space) +'em}}', + '\\@starttoc{' + latexCategory + '}', + '\\makeatother' + ] + elt = [RawBlock('tex', ''.join(latex))] + else: + if category in collections: + # Prepare the list + elements = [] -def replacing(key, value, format, meta): - global replace - if key == 'Str' and value == '#': - return Str(replace) - -def hasCiteShortCut(meta): - if not hasattr(hasCiteShortCut, 'value'): - if 'pandoc-numbering' in meta and \ - meta['pandoc-numbering']['t'] == 'MetaMap' and \ - 'cite-shortcut' in meta['pandoc-numbering']['c'] and\ - meta['pandoc-numbering']['c']['cite-shortcut']['t'] == 'MetaBool' and\ - meta['pandoc-numbering']['c']['cite-shortcut']['c']: - hasCiteShortCut.value = True - else: - hasCiteShortCut.value = False - return hasCiteShortCut.value + # Loop on the collection + for tag in collections[category]: + + # Add an item to the list + text = information[tag]['toc'] + + if pandocVersion() < '1.16': + # pandoc 1.15 + link = Link(text, ['#' + tag, '']) + else: + # pandoc 1.16 + link = Link(['', [], []], text, ['#' + tag, '']) + elements.append([Plain([link])]) + + # Add a bullet list + elt = [BulletList(elements)] + else: + + # Add nothing + elt = [] + + # Add a new listing + listings = listings + [Header(1, ['', ['unnumbered'], []], title)] + elt + + # Add listings to the document + doc[1] = listings + doc[1] + +def getFormat(category, meta): + if not hasattr(getFormat, 'value'): + getFormat.value = {} + + if 'pandoc-numbering' in meta and meta['pandoc-numbering']['t'] == 'MetaList': + + # Loop on all listings definition + for definition in meta['pandoc-numbering']['c']: + + if definition['t'] == 'MetaMap' and\ + 'format' in definition['c'] and\ + 'category' in definition['c'] and\ + definition['c']['category']['t'] == 'MetaInlines' and\ + len(definition['c']['category']['c']) == 1 and\ + definition['c']['category']['c'][0]['t'] == 'Str' and\ + definition['c']['format']['t'] == 'MetaBool': + + getFormat.value[definition['c']['category']['c'][0]['c']] = definition['c']['format']['c'] + + if not category in getFormat.value: + + getFormat.value[category] = True + + return getFormat.value[category] + +def getCiteShortCut(category, meta): + if not hasattr(getCiteShortCut, 'value'): + getCiteShortCut.value = {} + + if 'pandoc-numbering' in meta and meta['pandoc-numbering']['t'] == 'MetaList': + + # Loop on all listings definition + for definition in meta['pandoc-numbering']['c']: + + if definition['t'] == 'MetaMap' and\ + 'cite-shortcut' in definition['c'] and\ + 'category' in definition['c'] and\ + definition['c']['category']['t'] == 'MetaInlines' and\ + len(definition['c']['category']['c']) == 1 and\ + definition['c']['category']['c'][0]['t'] == 'Str' and\ + definition['c']['cite-shortcut']['t'] == 'MetaBool': + + getCiteShortCut.value[definition['c']['category']['c'][0]['c']] = definition['c']['cite-shortcut']['c'] + + if not category in getCiteShortCut.value: + + getCiteShortCut.value[category] = False + + return getCiteShortCut.value[category] def getDefaultLevels(category, meta): - global headerRegex if not hasattr(getDefaultLevels, 'value'): + getDefaultLevels.value = {} - if category not in getDefaultLevels.value: - levelInf = 0 - levelSup = 0 - if 'pandoc-numbering' in meta and \ - meta['pandoc-numbering']['t'] == 'MetaMap' and \ - 'sectioning' in meta['pandoc-numbering']['c'] and\ - meta['pandoc-numbering']['c']['sectioning']['t'] == 'MetaMap' and\ - category in meta['pandoc-numbering']['c']['sectioning']['c'] and\ - meta['pandoc-numbering']['c']['sectioning']['c'][category]['t'] == 'MetaInlines': - if len(meta['pandoc-numbering']['c']['sectioning']['c'][category]['c']) == 1 and\ - meta['pandoc-numbering']['c']['sectioning']['c'][category]['c'][0]['t'] == 'Str': - match = re.match('^' + headerRegex + '$', meta['pandoc-numbering']['c']['sectioning']['c'][category]['c'][0]['c']) - if match: - # Compute the levelInf and levelSup values - levelInf = len(match.group('hidden')) // 2 - levelSup = len(match.group('header')) // 2 - getDefaultLevels.value[category] = [levelInf, levelSup] + + if 'pandoc-numbering' in meta and meta['pandoc-numbering']['t'] == 'MetaList': + + # Loop on all listings definition + for definition in meta['pandoc-numbering']['c']: + + if definition['t'] == 'MetaMap' and\ + 'category' in definition['c'] and\ + definition['c']['category']['t'] == 'MetaInlines' and\ + len(definition['c']['category']['c']) == 1 and\ + definition['c']['category']['c'][0]['t'] == 'Str': + + levelInf = 0 + levelSup = 0 + + if 'sectioning' in definition['c'] and\ + definition['c']['sectioning']['t'] == 'MetaInlines' and\ + len(definition['c']['sectioning']['c']) == 1 and\ + definition['c']['sectioning']['c'][0]['t'] == 'Str': + + global headerRegex + + match = re.match('^' + headerRegex + '$', definition['c']['sectioning']['c'][0]['c']) + if match: + # Compute the levelInf and levelSup values + levelInf = len(match.group('hidden')) // 2 + levelSup = len(match.group('header')) // 2 + + else: + + if 'first' in definition['c'] and definition['c']['first']['t'] == 'MetaString': + try: + levelInf = max(min(int(definition['c']['first']['c']) - 1, 6), 0) + except ValueError: + pass + + if 'last' in definition['c'] and definition['c']['last']['t'] == 'MetaString': + try: + levelSup = max(min(int(definition['c']['last']['c']), 6), levelInf) + except ValueError: + pass + + getDefaultLevels.value[definition['c']['category']['c'][0]['c']] = [levelInf, levelSup] + + if not category in getDefaultLevels.value: + + getDefaultLevels.value[category] = [0, 0] + return getDefaultLevels.value[category] +def getClasses(category, meta): + if not hasattr(getClasses, 'value'): + + getClasses.value = {} + + if 'pandoc-numbering' in meta and meta['pandoc-numbering']['t'] == 'MetaList': + + # Loop on all listings definition + for definition in meta['pandoc-numbering']['c']: + + if definition['t'] == 'MetaMap' and\ + 'category' in definition['c'] and\ + definition['c']['category']['t'] == 'MetaInlines' and\ + len(definition['c']['category']['c']) == 1 and\ + definition['c']['category']['c'][0]['t'] == 'Str': + + if 'classes' in definition['c'] and definition['c']['classes']['t'] == 'MetaList': + + classes = [] + + for elt in definition['c']['classes']['c']: + classes.append(stringify(elt)) + + getClasses.value[definition['c']['category']['c'][0]['c']] = classes + + if not category in getClasses.value: + + getClasses.value[category] = [category] + + return getClasses.value[category] + def pandocVersion(): if not hasattr(pandocVersion, 'value'): p = subprocess.Popen(['pandoc', '-v'], stdout=subprocess.PIPE,stderr=subprocess.PIPE) diff --git a/setup.py b/setup.py index 4e7cfa7..8f4bfd3 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version='1.0.0', + version='2.0.0', # The project's description description='A pandoc filter for automatic numbering', diff --git a/tests/test_listings.py b/tests/test_listings.py new file mode 100644 index 0000000..8f3e002 --- /dev/null +++ b/tests/test_listings.py @@ -0,0 +1,295 @@ +# This Python file uses the following encoding: utf-8 + +from unittest import TestCase +from pandocfilters import Para, Str, Space, Header, BulletList, Span, Strong, Plain, Link, RawBlock + +import json + +import pandoc_numbering + +def init(): + pandoc_numbering.count = {} + pandoc_numbering.information = {} + pandoc_numbering.collections = {} + pandoc_numbering.headers = [0, 0, 0, 0, 0, 0] + if hasattr(pandoc_numbering.getCiteShortCut, 'value'): + delattr(pandoc_numbering.getCiteShortCut, 'value') + if hasattr(pandoc_numbering.getDefaultLevels, 'value'): + delattr(pandoc_numbering.getDefaultLevels, 'value') + if hasattr(pandoc_numbering.getClasses, 'value'): + delattr(pandoc_numbering.getClasses, 'value') + if hasattr(pandoc_numbering.getFormat, 'value'): + delattr(pandoc_numbering.getFormat, 'value') + +def createLink(attributes, text, reference_title): + if pandoc_numbering.pandocVersion() < '1.16': + return Link(text, reference_title) + else: + return Link(attributes, text, reference_title) + +def test_listing_classic(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'listing': { + 't': 'MetaInlines', + 'c': [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')] + }, + 'sectioning': { + 't': 'MetaInlines', + 'c': [Str('-.+.')] + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + src = Para([Str(u'Exercise'), Space(), Str('(test)'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + doc = [[{'unMeta': meta}], []] + pandoc_numbering.addListings(doc, '', meta) + + dest = [ + Header( + 1, + ['', ['unnumbered'], []], + [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')] + ), + BulletList([ + [Plain([createLink(['', [], []], [Str('0.0.1'), Space(), Str('Exercise')], ['#exercise:0.0.1', ''])])], + [Plain([createLink(['', [], []], [Str('0.0.2'), Space(), Str('test')], ['#exercise:0.0.2', ''])])] + ]) + ] + + assert json.loads(json.dumps(doc[1])) == json.loads(json.dumps(dest)) + +def test_listing_latex(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'listing': { + 't': 'MetaInlines', + 'c': [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')] + }, + 'sectioning': { + 't': 'MetaInlines', + 'c': [Str('-.+.')] + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + src = Para([Str(u'Exercise'), Space(), Str('(test)'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + + doc = [[{'unMeta': meta}], []] + pandoc_numbering.addListings(doc, 'latex', meta) + + dest = [ + Header(1, ['', ['unnumbered'], []], [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')]), + RawBlock( + 'tex', + ''.join([ + '\\hypersetup{linkcolor=black}', + '\\makeatletter', + '\\newcommand*\\l@exercise{\\@dottedtocline{1}{1.5em}{3.3em}}', + '\\@starttoc{exercise}', + '\\makeatother' + ]) + ) + ] + + assert json.loads(json.dumps(doc[1])) == json.loads(json.dumps(dest)) + +def test_listing_latex_color(): + init() + + meta = { + 'toccolor': { + 't': 'MetaInlines', + 'c': [Str('blue')] + }, + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'listing': { + 't': 'MetaInlines', + 'c': [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')] + }, + 'sectioning': { + 't': 'MetaInlines', + 'c': [Str('-.+.')] + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + src = Para([Str(u'Exercise'), Space(), Str('(test)'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + + doc = [[{'unMeta': meta}], []] + pandoc_numbering.addListings(doc, 'latex', meta) + + dest = [ + Header(1, ['', ['unnumbered'], []], [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')]), + RawBlock( + 'tex', + ''.join([ + '\\hypersetup{linkcolor=blue}', + '\\makeatletter', + '\\newcommand*\\l@exercise{\\@dottedtocline{1}{1.5em}{3.3em}}', + '\\@starttoc{exercise}', + '\\makeatother' + ]) + ) + ] + + assert json.loads(json.dumps(doc[1])) == json.loads(json.dumps(dest)) + +def test_listing_latex_tab_space(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'listing': { + 't': 'MetaInlines', + 'c': [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')] + }, + 'sectioning': { + 't': 'MetaInlines', + 'c': [Str('-.+.')] + }, + 'tab': { + 't': 'MetaString', + 'c': '2' + }, + 'space': { + 't': 'MetaString', + 'c': '4' + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + src = Para([Str(u'Exercise'), Space(), Str('(test)'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + + doc = [[{'unMeta': meta}], []] + pandoc_numbering.addListings(doc, 'latex', meta) + + dest = [ + Header(1, ['', ['unnumbered'], []], [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')]), + RawBlock( + 'tex', + '\\hypersetup{linkcolor=black}\\makeatletter\\newcommand*\\l@exercise{\\@dottedtocline{1}{2.0em}{4.0em}}\\@starttoc{exercise}\\makeatother' + ) + ] + + assert json.loads(json.dumps(doc[1])) == json.loads(json.dumps(dest)) + +def test_listing_latex_tab_space_error(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'listing': { + 't': 'MetaInlines', + 'c': [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')] + }, + 'sectioning': { + 't': 'MetaInlines', + 'c': [Str('-.+.')] + }, + 'tab': { + 't': 'MetaString', + 'c': 'a' + }, + 'space': { + 't': 'MetaString', + 'c': 'b' + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + src = Para([Str(u'Exercise'), Space(), Str('(test)'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], 'latex', meta) + + doc = [[{'unMeta': meta}], []] + pandoc_numbering.addListings(doc, 'latex', meta) + + dest = [ + Header(1, ['', ['unnumbered'], []], [Str('Listings'), Space(), Str('of'), Space(), Str('exercises')]), + RawBlock( + 'tex', + '\\hypersetup{linkcolor=black}\\makeatletter\\newcommand*\\l@exercise{\\@dottedtocline{1}{1.5em}{3.3em}}\\@starttoc{exercise}\\makeatother' + ) + ] + + assert json.loads(json.dumps(doc[1])) == json.loads(json.dumps(dest)) + diff --git a/tests/test_numbering.py b/tests/test_numbering.py index 22ebdc5..48e314c 100644 --- a/tests/test_numbering.py +++ b/tests/test_numbering.py @@ -1,23 +1,38 @@ # This Python file uses the following encoding: utf-8 + from unittest import TestCase from pandocfilters import Para, Str, Space, Span, Strong, RawInline, Emph, Header +import json + import pandoc_numbering def init(): pandoc_numbering.count = {} pandoc_numbering.information = {} + pandoc_numbering.collections = {} pandoc_numbering.headers = [0, 0, 0, 0, 0, 0] - if hasattr(pandoc_numbering.hasCiteShortCut, 'value'): - delattr(pandoc_numbering.hasCiteShortCut, 'value') + if hasattr(pandoc_numbering.getCiteShortCut, 'value'): + delattr(pandoc_numbering.getCiteShortCut, 'value') if hasattr(pandoc_numbering.getDefaultLevels, 'value'): delattr(pandoc_numbering.getDefaultLevels, 'value') + if hasattr(pandoc_numbering.getClasses, 'value'): + delattr(pandoc_numbering.getClasses, 'value') + if hasattr(pandoc_numbering.getFormat, 'value'): + delattr(pandoc_numbering.getFormat, 'value') def test_numbering(): init() src = Para([Str(u'Exercise'), Space(), Str(u'#')]) - dest = Para([Span([u'exercise:1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])])]) + dest = Para([ + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -25,12 +40,26 @@ def test_numbering_prefix_single(): init() src = Para([Str(u'Exercise'), Space(), Str(u'#ex:')]) - dest = Para([Span([u'ex:1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])])]) + dest = Para([ + Span( + [u'ex:1', ['pandoc-numbering-text', 'ex'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest src = Para([Str(u'Exercise'), Space(), Str(u'#')]) - dest = Para([Span([u'exercise:1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])])]) + dest = Para([ + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -39,8 +68,30 @@ def test_numbering_latex(): src = Para([Str(u'Exercise'), Space(), Str(u'#')]) dest = Para([ - RawInline(u'tex', u'\\phantomsection'), - Span([u'exercise:1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])]) + RawInline(u'tex', u'\\phantomsection\\addcontentsline{exercise}{exercise}{\\protect\\numberline {1}{\\ignorespaces Exercise}}'), + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) + + assert pandoc_numbering.numbering(src['t'], src['c'], 'latex', {}) == dest + + init() + + src = Para([Str(u'Exercise'), Space(), Str(u'(The'), Space(), Str(u'title)'), Space(), Str(u'#')]) + dest = Para([ + RawInline(u'tex', u'\\phantomsection\\addcontentsline{exercise}{exercise}{\\protect\\numberline {1}{\\ignorespaces The title}}'), + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]), + Space(), + Emph([Str(u'('), Str(u'The'), Space(), Str(u'title'), Str(u')')]) + ] + ) ]) assert pandoc_numbering.numbering(src['t'], src['c'], 'latex', {}) == dest @@ -52,7 +103,14 @@ def test_numbering_double(): pandoc_numbering.numbering(src['t'], src['c'], '', {}) src = Para([Str(u'Exercise'), Space(), Str(u'#')]) - dest = Para([Span([u'exercise:2', [], []], [Strong( [Str(u'Exercise'), Space(), Str(u'2')])])]) + dest = Para([ + Span( + [u'exercise:2', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'2')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -62,11 +120,11 @@ def test_numbering_title(): src = Para([Str(u'Exercise'), Space(), Str(u'(The'), Space(), Str(u'title)'), Space(), Str(u'#')]) dest = Para([ Span( - [u'exercise:1', [], []], + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], [ Strong([Str(u'Exercise'), Space(), Str(u'1')]), Space(), - Emph([Str(u'(The'), Space(), Str(u'title)')]) + Emph([Str(u'('), Str(u'The'), Space(), Str(u'title'), Str(u')')]) ] ) ]) @@ -77,7 +135,14 @@ def test_numbering_level(): init() src = Para([Str(u'Exercise'), Space(), Str(u'+.+.#')]) - dest = Para([Span([u'exercise:0.0.1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'0.0.1')])])]) + dest = Para([ + Span( + [u'exercise:0.0.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'0.0.1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -88,12 +153,26 @@ def test_numbering_level(): pandoc_numbering.numbering(src['t'], src['c'], '', {}) src = Para([Str(u'Exercise'), Space(), Str(u'+.+.#')]) - dest = Para([Span( [u'exercise:1.1.1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1.1.1')])])]) + dest = Para([ + Span( + [u'exercise:1.1.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1.1.1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest src = Para([Str(u'Exercise'), Space(), Str(u'+.+.#')]) - dest = Para([Span([u'exercise:1.1.2', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1.1.2')])])]) + dest = Para([ + Span( + [u'exercise:1.1.2', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1.1.2')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -101,7 +180,14 @@ def test_numbering_level(): pandoc_numbering.numbering(src['t'], src['c'], '', {}) src = Para([Str(u'Exercise'), Space(), Str(u'+.+.#')]) - dest = Para([Span([u'exercise:1.2.1', [], []], [Strong( [Str(u'Exercise'), Space(), Str(u'1.2.1')])])]) + dest = Para([ + Span( + [u'exercise:1.2.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1.2.1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -112,7 +198,14 @@ def test_numbering_unnumbered(): pandoc_numbering.numbering(src['t'], src['c'], '', {}) src = Para([Str(u'Exercise'), Space(), Str(u'+.#')]) - dest = Para([Span([u'exercise:0.1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'0.1')])])]) + dest = Para([ + Span( + [u'exercise:0.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'0.1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -123,12 +216,26 @@ def test_numbering_hidden(): pandoc_numbering.numbering(src['t'], src['c'], '', {}) src = Para([Str(u'Exercise'), Space(), Str(u'-.#exercise:one')]) - dest = Para([Span([u'exercise:one', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])])]) + dest = Para([ + Span( + [u'exercise:one', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest src = Para([Str(u'Exercise'), Space(), Str(u'-.#')]) - dest = Para([Span([u'exercise:1.2', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'2')])])]) + dest = Para([ + Span( + [u'exercise:1.2', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'2')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -136,17 +243,38 @@ def test_numbering_hidden(): pandoc_numbering.numbering(src['t'], src['c'], '', {}) src = Para([Str(u'Exercise'), Space(), Str(u'-.#')]) - dest = Para([Span([u'exercise:2.1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])])]) + dest = Para([ + Span( + [u'exercise:2.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest src = Para([Str(u'Exercise'), Space(), Str(u'+.#')]) - dest = Para([Span([u'exercise:2.2', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'2.2')])])]) + dest = Para([ + Span( + [u'exercise:2.2', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'2.2')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest src = Para([Str(u'Exercise'), Space(), Str(u'#')]) - dest = Para([Span([u'exercise:1', [], []], [Strong([Str(u'Exercise'), Space(), Str(u'1')])])]) + dest = Para([ + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) assert pandoc_numbering.numbering(src['t'], src['c'], '', {}) == dest @@ -159,25 +287,82 @@ def test_numbering_sharp_sharp(): assert src == dest -def test_numbering_sectioning(): +def test_numbering_sectioning_string(): init() meta = { 'pandoc-numbering': { - 't': 'MetaMap', - 'c': { - 'sectioning': { + 't': 'MetaList', + 'c': [ + { 't': 'MetaMap', 'c': { - 'exercise': { - 'c': [{'c': '-.+.', 't': 'Str'}], - 't': 'MetaInlines' + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'sectioning': { + 't': 'MetaInlines', + 'c': [Str('-.+.')] } } } - } + ] + } + } + + src = Header(1, [u'first-chapter', [], []], [Str(u'First'), Space(), Str('chapter')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Header(1, [u'second-chapter', [], []], [Str(u'Second'), Space(), Str('chapter')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Header(2, [u'first-section', [], []], [Str(u'First'), Space(), Str('section')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Header(2, [u'second-section', [], []], [Str(u'Second'), Space(), Str('section')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + dest = Para([ + Span( + [u'exercise:2.2.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'2.1')]) + ] + ) + ]) + + assert pandoc_numbering.numbering(src['t'], src['c'], '', meta) == dest + +def test_numbering_sectioning_map(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'first': { + 'c': 2, + 't': 'MetaString' + }, + 'last': { + 'c': 2, + 't': 'MetaString' + } + } + } + ] } } + src = Header(1, [u'first-chapter', [], []], [Str(u'First'), Space(), Str('chapter')]) pandoc_numbering.numbering(src['t'], src['c'], '', meta) @@ -191,8 +376,135 @@ def test_numbering_sectioning(): pandoc_numbering.numbering(src['t'], src['c'], '', meta) src = Para([Str(u'Exercise'), Space(), Str(u'#')]) - dest = Para([Str(u'Exercise'), Space(), Str(u'2.1')]) + dest = Para([ + Span( + [u'exercise:2.2.1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'2.1')]) + ] + ) + ]) + + assert pandoc_numbering.numbering(src['t'], src['c'], '', meta) == dest + +def test_numbering_sectioning_map_error(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'first': { + 'c': 'a', + 't': 'MetaString' + }, + 'last': { + 'c': 'b', + 't': 'MetaString' + } + } + } + ] + } + } + + src = Header(1, [u'first-chapter', [], []], [Str(u'First'), Space(), Str('chapter')]) pandoc_numbering.numbering(src['t'], src['c'], '', meta) - assert src == dest + src = Header(1, [u'second-chapter', [], []], [Str(u'Second'), Space(), Str('chapter')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Header(2, [u'first-section', [], []], [Str(u'First'), Space(), Str('section')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Header(2, [u'second-section', [], []], [Str(u'Second'), Space(), Str('section')]) + pandoc_numbering.numbering(src['t'], src['c'], '', meta) + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + dest = Para([ + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercise'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) + + assert pandoc_numbering.numbering(src['t'], src['c'], '', meta) == dest + +def test_classes(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'classes': { + 't': 'MetaList', + 'c': [{'t': 'MetaInlines', 'c': [{'t': 'Str', 'c': 'my-class'}]}] + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + dest = Para([ + Span( + [u'exercise:1', ['pandoc-numbering-text', 'my-class'], []], + [ + Strong([Str(u'Exercise'), Space(), Str(u'1')]) + ] + ) + ]) + + assert pandoc_numbering.numbering(src['t'], src['c'], '', meta) == dest + +def test_format(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaMap', + 'c': { + 'format': { + 't': 'MetaMap', + 'c': { + 'exercise': { + 'c': False, + 't': 'MetaBool' + } + } + } + } + } + } + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + dest = json.loads(json.dumps(Para([ + Span( + [u'exercise:1', ['pandoc-numbering-text', 'exercice'], []], + [ + Span(['', ['description'], []], [Str(u'Exercise')]), + Span(['', ['number'], []], [Str(u'1')]), + Span(['', ['title'], []], []) + ] + ) + ]))) + + json.loads(json.dumps(pandoc_numbering.numbering(src['t'], src['c'], '', meta))) == dest diff --git a/tests/test_referencing.py b/tests/test_referencing.py index a541a14..f8b8ba9 100644 --- a/tests/test_referencing.py +++ b/tests/test_referencing.py @@ -1,7 +1,7 @@ # This Python file uses the following encoding: utf-8 + from unittest import TestCase -from pandocfilters import Para, Str, Space, Link, Header, Cite -import sys +from pandocfilters import Para, Str, Space, Link, Header, Cite, Span import json import pandoc_numbering @@ -10,10 +10,14 @@ def init(): pandoc_numbering.count = {} pandoc_numbering.information = {} pandoc_numbering.headers = [0, 0, 0, 0, 0, 0] - if hasattr(pandoc_numbering.hasCiteShortCut, 'value'): - delattr(pandoc_numbering.hasCiteShortCut, 'value') + if hasattr(pandoc_numbering.getCiteShortCut, 'value'): + delattr(pandoc_numbering.getCiteShortCut, 'value') if hasattr(pandoc_numbering.getDefaultLevels, 'value'): delattr(pandoc_numbering.getDefaultLevels, 'value') + if hasattr(pandoc_numbering.getClasses, 'value'): + delattr(pandoc_numbering.getClasses, 'value') + if hasattr(pandoc_numbering.getFormat, 'value'): + delattr(pandoc_numbering.getFormat, 'value') def createLink(attributes, text, reference_title): if pandoc_numbering.pandocVersion() < '1.16': @@ -27,35 +31,75 @@ def test_referencing_simple(): src = Para([Str(u'Exercise'), Space(), Str(u'#exercise:first')]) pandoc_numbering.numbering(src['t'], src['c'], u'', {}) - src = json.loads(json.dumps(createLink(['', [], []], [], [u'#exercise:first', u'']))) - dest = json.loads(json.dumps(createLink(['', [], []], [Str(u'Exercise'), Space(), Str(u'1')], [u'#exercise:first', u'']))) + src = json.loads(json.dumps(createLink( + ['', [], []], + [], + [u'#exercise:first', u''] + ))) + dest = json.loads(json.dumps(createLink( + ['', [], []], + [ + Str(u'Exercise'), + Space(), + Str(u'1') + ], + [u'#exercise:first', u''] + ))) pandoc_numbering.referencing(src['t'], src['c'], '', {}) - assert src == dest + assert json.loads(json.dumps(src)) == dest def test_referencing_title(): init() - src = Para([Str(u'Exercise'), Space(), Str(u'#exercise:first')]) + src = Para([Str(u'Exercise'), Space(), Str(u'(The'), Space(), Str(u'title)'), Space(), Str(u'-.+.#exercise:first')]) pandoc_numbering.numbering(src['t'], src['c'], u'', {}) - src = json.loads(json.dumps(createLink(['', [], []], [], [u'#exercise:first', u'This is the exercise #']))) + src = json.loads(json.dumps(createLink( + ['', [], []], + [], + [u'#exercise:first', u'#d #D #t #T #s #g #c #n #'] + ))) dest = json.loads(json.dumps(createLink( ['', [], []], - [Str(u'Exercise'), Space(), Str(u'1')], [u'#exercise:first', u'This is the exercise 1'] + [ + Str(u'Exercise'), + Space(), + Str(u'0.1') + ], + [u'#exercise:first', u'exercise Exercise the title The title 0.0 0.0.1 1 0.1 0.1'] ))) pandoc_numbering.referencing(src['t'], src['c'], '', {}) - assert src == dest + assert json.loads(json.dumps(src)) == dest def test_referencing_prefix(): init() - src = Para([Str(u'Exercise'), Space(), Str(u'#exercise:first')]) + src = Para([Str(u'Exercise'), Space(), Str(u'(The'), Space(), Str(u'title)'), Space(), Str(u'#exercise:first')]) pandoc_numbering.numbering(src['t'], src['c'], u'', {}) - src = json.loads(json.dumps(createLink(['', [], []], [Str(u'exercise'), Space(), Str(u'#')], [u'#exercise:first', u'']))) - dest = json.loads(json.dumps(createLink(['', [], []], [Str(u'exercise'), Space(), Str(u'1')], [u'#exercise:first', u'']))) + src = json.loads(json.dumps(createLink( + ['', [], []], + [Str(u'#d#D#t#T#n#')], + [u'#exercise:first', u''] + ))) + dest = json.loads(json.dumps(createLink( + ['', [], []], + [ + Str(u'exercise'), + Str(u'Exercise'), + Str(u'the'), + Space(), + Str(u'title'), + Str(u'The'), + Space(), + Str(u'title'), + Str(u'1'), + Str(u'1') + ], + [u'#exercise:first', u''] + ))) pandoc_numbering.referencing(src['t'], src['c'], '', {}) assert src == dest @@ -94,10 +138,18 @@ def test_referencing_automatic(): pandoc_numbering.numbering(src['t'], src['c'], u'', {}) src = json.loads(json.dumps(createLink(['', [], []], [], [u'#exercise:1', u'']))) - dest = json.loads(json.dumps(createLink(['', [], []], [Str(u'Exercise'), Space(), Str(u'1')], [u'#exercise:1', u'']))) + dest = json.loads(json.dumps(createLink( + ['', [], []], + [ + Str(u'Exercise'), + Space(), + Str(u'1') + ], + [u'#exercise:1', u''] + ))) pandoc_numbering.referencing(src['t'], src['c'], '', {}) - assert src == dest + assert json.loads(json.dumps(src)) == dest def test_referencing_unexisting(): init() @@ -118,10 +170,18 @@ def test_referencing_headers(): pandoc_numbering.numbering(src['t'], src['c'], u'', {}) src = json.loads(json.dumps(createLink(['', [], []], [], [u'#theorem:first', u'']))) - dest = json.loads(json.dumps(createLink(['', [], []], [Str(u'Theorem'), Space(), Str(u'1.1')], [u'#theorem:first', u'']))) + dest = json.loads(json.dumps(createLink( + ['', [], []], + [ + Str(u'Theorem'), + Space(), + Str(u'1.1') + ], + [u'#theorem:first', u''] + ))) pandoc_numbering.referencing(src['t'], src['c'], '', {}) - assert src == dest + assert json.loads(json.dumps(src)) == dest src = json.loads(json.dumps(createLink( ['', [], []], @@ -152,16 +212,82 @@ def test_referencing_without_cite_shortcut(): def test_referencing_with_cite_shortcut(): init() + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('theorem')] + }, + 'cite-shortcut': { + 't': 'MetaBool', + 'c': True + } + } + } + ] + } + } + src = Para([Str(u'Theorem'), Space(), Str(u'#theorem:first')]) pandoc_numbering.numbering(src['t'], src['c'], u'', {}) src = json.loads(json.dumps(Cite([], [Str(u'@theorem:first')]))) dest = json.loads(json.dumps(createLink(['', [], []], [Str(u'1')], [u'#theorem:first', u'']))) - assert json.loads(json.dumps(pandoc_numbering.referencing( - src['t'], - src['c'], - '', - {'pandoc-numbering': {'c': {'cite-shortcut': {'c': True, 't': 'MetaBool'}}, 't': 'MetaMap'}} - ))) == dest + assert json.loads(json.dumps(pandoc_numbering.referencing(src['t'], src['c'], '', meta))) == dest + +def test_referencing_format(): + init() + + meta = { + 'pandoc-numbering': { + 't': 'MetaList', + 'c': [ + { + 't': 'MetaMap', + 'c': { + 'category': { + 't': 'MetaInlines', + 'c': [Str('exercise')] + }, + 'format': { + 't': 'MetaBool', + 'c': False + } + } + } + ] + } + } + + src = Para([Str(u'Exercise'), Space(), Str(u'#')]) + pandoc_numbering.numbering(src['t'], src['c'], u'', meta) + + src = json.loads(json.dumps(createLink(['', [], []], [], [u'#exercise:1', u'']))) + dest = json.loads(json.dumps(createLink( + ['', [], []], + [ + Span( + ['', ['pandoc-numbering-link', 'exercise'], []], + [ + Span(['', ['description'], []], [Str(u'Exercise')]), + Span(['', ['title'], []], []), + Span(['', ['local'], []], [Str(u'1')]), + Span(['', ['global'], []], [Str(u'1')]), + Span(['', ['section'], []], [Str(u'')]), + ] + ) + ], + [u'#exercise:1', u''] + ))) + + pandoc_numbering.referencing(src['t'], src['c'], '', meta) + + assert json.loads(json.dumps(src)) == dest +