예제 #1
0
def footnotesToHtml(wb):

  matchFN = re.compile("<fn\s+(.*?)/?>")
  footnotes = {}

  # footnote marks in text
  i = 0
  while i < len(wb):
    off = 0
    line = wb[i]
    while True:
      m = matchFN.search(line, off)
      if not m:
        break
      opts = m.group(1)
      args = parseTagAttributes("fn", opts, [ "id", "target" ])
      fmid = args["id"]
      if not "target" in args:
        fatal("Missing internal target in fn: " + line)
      target = args["target"]
      dprint(1, "id: " + fmid + ", target: " + target)
      if fmid in footnotes and footnotes[fmid] == target:
        cprint("warning: footnote id <fn id='" + fmid + "'> occurs multiple times.  <footnote> link will be to the first.")
        repl = "<a href='#f{0}' style='text-decoration:none'><sup><span style='font-size:0.9em'>{1}</span></sup></a>".format(target, fmid)
      else:
        footnotes[fmid] = target
        repl = "<a id='r{0}'/><a href='#f{0}' style='text-decoration:none'><sup><span style='font-size:0.9em'>{1}</span></sup></a>".format(target, fmid)
      l = line[0:m.start(0)] + repl
      off = len(l)    # Next loop
      line = l + line[m.end(0):]
    wb[i] = line
    i += 1

  # footnote targets and text
  i = 0
  while i < len(wb):
    m = re.match("<footnote\s+(.*?)>", wb[i])
    if m:
      opts = m.group(1)
      args = parseTagAttributes("footnote", opts, [ "id", "target" ])
      fnid = args["id"]
      target = args["target"]
      wb[i] = "<div id='f{0}'><a href='#r{0}'>{1}</a></div>".format(target, fnid)
      while not re.match("<\/footnote>", wb[i]):
        i += 1
      wb[i] = "</div> <!-- footnote end -->"
    i += 1
예제 #2
0
 def defineTemplate(self, opts, block):
   attributes = parseTagAttributes("template", opts, [ "name", "type" ])
   if not "name" in attributes or not "type" in attributes:
     fatal("Template definition requires both name and type attributes: " + opts)
   name = attributes["name"]
   type = attributes["type"]
   dprint(1, "defining template name " + name + " of type " + type + ": " + str(block))
   self.add(type, name, block)
   return []
예제 #3
0
 def expandMacro(self, opts):
     attributes = parseTagAttributes("expand-macro", opts, [ "name", "vars" ])
     if not "name" in attributes:
       fatal("expand-macro: No macro name given: " + line)
     template = self.get([ "macro" ], attributes["name"])
     if "vars" in attributes:
       keys = parseOption("expand-macro", attributes["vars"])
     else:
       keys = {}
     return template.expand(keys)
예제 #4
0
  def footnoteRelocate(opts, block):

    opts = opts.strip()
    # Parse and recreate the footnote tag, to handle autonumbering footnotes
    args = parseTagAttributes("footnote", opts, [ "id" ])
    if not "id" in args:
      fatal("<footnote> does not have id attribute: " + opts)
    id = args["id"]
    target = None
    if id == '#':
      nonlocal footnotec
      id = str(footnotec)
      if mode == asterisk and footnotec <= len(footnoteMarkers):
        displayid = footnoteMarkers[footnotec-1]
      else:
        displayid = "[" + id + "]"
      footnotec += 1
    else:
      if id in footnoteMarkers:
        i = footnoteMarkers.index(id)
        displayid = id  # Don't add the square brackets
        target = footnoteMarkersText[i]
        if not reset:
          fatal("Use of explicit footnote symbols requires footnote-location to be set to either asterisk or heading-reset: " + str(opts))
      else:
        displayid = "[" + id + "]"
    if target == None:
      target = id
    if reset:
      target += "_" + str(footnoteChapter)
    opts = "id='" + displayid + "' target='" + target + "'"

    # Handle fn tags inside footnotes!
    relocateFootnotes(block)

    # Recreate the block
    block.insert(0, "<footnote " + opts + ">")
    block.append("</footnote>")

    if emitAtReference:
      noteMap[target] = block
      return []

    # If we aren't supposed to move footnotes, do nothing
    if mode == none:
      return block

    # Otherwise accumulate them for emitting elsewhere
    nonlocal notes
    notes.append(block)

    # Clear the current location of the footnote
    return []
예제 #5
0
def FNtoHtml(wb):
  matchFN = re.compile("<fn\s+(.*?)/?>")
  footnotes = {}

  # footnote marks in text
  i = 0
  while i < len(wb):
    off = 0
    line = wb[i]
    block = [ ]
    while True:
      m = matchFN.search(line, off)
      if not m:
        break
      opts = m.group(1)
      args = parseTagAttributes("fn", opts, [ "id", "target" ])
      fmid = args["id"]
      if not "target" in args:
        fatal("Missing internal target in fn: " + line)
      target = args["target"]
      dprint(1, "id: " + fmid + ", target: " + target)
      repl = "<sup><span style='font-size:0.9em'>" + fmid + "</span></sup>"

      if target in noteMap:
        # Note no link when we are co-locating the reference with the footnote
        block.extend(noteMap[target])
        del noteMap[target]
      elif fmid in footnotes and footnotes[fmid] == target:
        wprint('multifootnote', "warning: footnote id <fn id='" + fmid + "'> occurs multiple times.  <footnote> link will be to the first. Line: >>>" + line + "<<<")
        repl = "<a href='#f{0}' style='text-decoration:none'>{1}</a>".format(target, repl)
      else:
        footnotes[fmid] = target
        repl = "<a id='r{0}'/><a href='#f{0}' style='text-decoration:none'>{1}</a>".format(target, repl)

      l = line[0:m.start(0)] + repl
      off = len(l)    # Next loop
      line = l + line[m.end(0):]
    wb[i] = line

    # Emit the footnote, right before the line with the footnote reference
    # If the line with the footnote reference is a paragraph start, need
    # to emit the footnote between the paragraph tag, and the rest of the
    # text on the first line of the paragraph
    if len(block) > 0:
      m = re.match("(<p.*?>)", wb[i])
      if m:
        block.insert(0, m.group(1))
        wb[i] = wb[i][len(m.group(1)):]
      wb[i:i] = block
      i += len(block)
    i += 1
예제 #6
0
def footnotesToSidenoteTags(wb):
  FNtoHtml(wb)

  # footnote targets and text
  i = 0
  while i < len(wb):
    m = re.match("<footnote\s+(.*?)>", wb[i])
    if m:
      opts = m.group(1)
      args = parseTagAttributes("footnote", opts, [ "id", "target" ])
      fnid = args["id"]
      target = args["target"]
      wb[i] = "<sidenote>" + fnid
      while not re.match("<\/footnote>", wb[i]):
        i += 1
      wb[i] = "</sidenote>"
    i += 1
예제 #7
0
def footnotesToHtmlTags(wb):
  FNtoHtml(wb)

  # footnote targets and text
  i = 0
  while i < len(wb):
    m = re.match("<footnote\s+(.*?)>", wb[i])
    if m:
      opts = m.group(1)
      args = parseTagAttributes("footnote", opts, [ "id", "target" ])
      fnid = args["id"]
      target = args["target"]
      wb[i] = "<div class='footnote-id' id='f{0}'><a href='#r{0}'>{1}</a></div>".format(target, fnid)
      while not re.match("<\/footnote>", wb[i]):
        i += 1
      wb[i] = "</div> <!-- footnote end -->"
    i += 1
예제 #8
0
  def chapterTemplates(self, lines, properties, meta):

    # Figure out what template name to use.
    if "template-chapter" in properties:
      chapterTemplateName = properties["template-chapter"]
    else:
      chapterTemplateName = "default"
    if "template-chapter-first" in properties:
      chapterTemplateNameFirst = properties["template-chapter-first"]
    else:
      chapterTemplateNameFirst = "default-first"

    dprint(1, "Chapter Template: Using first: " + chapterTemplateNameFirst + \
        ", subsequent: " + chapterTemplateName)

    # Now we can set the globals, since we have now extracted all the metadata
    self.setGlobals(meta)

    # Figure out which templates we are going to use.
    tFirst = self.get([ "chapter" ], chapterTemplateNameFirst)
    t = self.get([ "chapter" ], chapterTemplateName)

    regexMacro = re.compile("<expand-macro\s+(.*?)/?>")
    i = 0
    first = True
    while i < len(lines):
      line = lines[i]
      if line.startswith("<chap-head"):
        keys = {}
        opts, keys["chap-head"] = parseLineEntry("chap-head", line)
        j = i+1
        while j < len(lines) and re.match(lines[j], "^\s*$"):
          j += 1
        if j == len(lines):
          fatal("End of file after <chap-head>")
        if opts !=  "":
          attributes = parseTagAttributes("chap-head", opts, [ "vars" ])
          dprint(1, "<chap-head> attributes: " + str(attributes))
          if "vars" in attributes:
            vars = parseOption("chap-head", attributes["vars"])
            dprint(1, "<chap-head> vars: " + str(vars))
            keys.update(vars)

        line = lines[j]
        if line.startswith("<sub-head"):
          opts, keys["sub-head"] = parseLineEntry("sub-head", line)
        else:
          # Do not eat this line!
          j -= 1

        # If the first we've seen, it starts the book
        if first:
          templ = tFirst
          first = False
        else:
          templ = t

        dprint(1, "expand keys: " + str(keys))
        replacement = templ.expand(keys)
        dprint(2, "replace " + str(lines[i:j+1]) + " with " + str(replacement))
        lines[i:j+1] = replacement
        i += len(replacement)
        continue

      if line.startswith("<sub-head>"):
        fatal("Found <sub-head> not after a <chap-head>: " + line)

      # What about multiple macro expansions on a line?  Or recursion?
      # Make it simpler for now by just punting: if you expand, then we move on
      # to the next line.
      m = regexMacro.search(line)
      if m:
        opts = m.group(1)
        attributes = parseTagAttributes("expand-macro", opts, [ "name", "vars" ])
        if not "name" in attributes:
          fatal("expand-macro: No macro name given: " + line)
        template = self.get([ "macro" ], attributes["name"])
        if "vars" in attributes:
          keys = parseOption("expand-macro", attributes["vars"])
        else:
          keys = {}
        replacement = template.expand(keys)
        prefix = line[:m.start(0)]
        suffix = line[m.end(0):]

        if len(replacement) == 0:
          # If the template returns nothing, then you end up with a single line of
          # the prefix and suffix around the <expand-macro>
          replacement = [ prefix + suffix ]
        else:
          # Otherwise the prefix goes on the first line; and the suffix at the end of
          # the last; which might be the same single line.
          replacement[0] = prefix + replacement[0]
          replacement[-1] = replacement[-1] + suffix
        lines[i:i+1] = replacement
        i += len(replacement)
        continue

      i += 1
예제 #9
0
  def processLine(i, line):
    nonlocal fnc, footnotec

    # Process <fn> tags, fixing id='#' with an appropriate number
    # Loop, can be multiple on a line.
    off = 0
    while True:
      m = matchFN.search(line, off)
      if not m:
        break
      opts = m.group(1)
      args = parseTagAttributes("fn", opts, [ "id" ])
      if not "id" in args:
        fatal("<fn> does not have id attribute: " + line)
      id = args["id"]
      target = None
      if id == '#':
        id = str(fnc)
        if mode == asterisk and fnc <= len(footnoteMarkers):
          displayid = footnoteMarkers[fnc-1]
        else:
          displayid = "[" + id + "]"
        fnc += 1
      else:
        if id in footnoteMarkers:
          i = footnoteMarkers.index(id)
          displayid = id  # Don't add the square brackets
          target = footnoteMarkersText[i]
        else:
          displayid = "[" + id + "]"
      if target == None:
        target = id
      if reset:
        nonlocal footnoteChapter
        target += "_" + str(footnoteChapter)
      opts = "id='" + displayid + "' target='" + target + "'"
      l = line[:m.start(0)] + "<fn " + opts + ">"
      off = len(l)    # Start next loop after end of this
      line = l + line[m.end(0):]

    # Are we going to emit it here?
    # Always emit if we hit a genfootnotes,
    # emit when we hit a heading, but only in heading mode.
    emit = False
    if line.startswith("<genfootnotes>"):
      emit = True
      line = None       # Remove the line, we don't want it!
    elif emitAtHeading:
      if line.startswith("<heading"):
        emit = True

    # If there weren't any, forget it, nothing to do
    if len(notes) == 0:
      emit = False

    if not emit:
      if line == None:
        return []
      else:
        return [ line ]

    all = formatNotes(line)

    # If our mode is reset, then whenever we emit, we reset our counters
    if reset:
      fnc = 1
      footnotec = 1
      footnoteChapter += 1

    return all