Beispiel #1
0
    def add_child(self, tag, offset):
        """ Add block of type tag as a child of the tip.  If the tip can't
        accept children, close and finalize it and try its parent,
        and so on til we find a block that can accept children."""
        block_class = getattr(import_module('CommonMark.blocks'),
                              to_camel_case(self.tip.t))
        while not block_class.can_contain(tag):
            self.finalize(self.tip, self.line_number - 1)
            block_class = getattr(import_module('CommonMark.blocks'),
                                  to_camel_case(self.tip.t))

        column_number = offset + 1
        new_block = Node(tag, [[self.line_number, column_number], [0, 0]])
        new_block.string_content = ''
        self.tip.append_child(new_block)
        self.tip = new_block
        return new_block
Beispiel #2
0
    def add_child(self, tag, offset):
        """ Add block of type tag as a child of the tip.  If the tip can't
        accept children, close and finalize it and try its parent,
        and so on til we find a block that can accept children."""
        block_class = getattr(import_module('CommonMark.blocks'),
                              to_camel_case(self.tip.t))
        while not block_class.can_contain(tag):
            self.finalize(self.tip, self.line_number - 1)
            block_class = getattr(
                import_module('CommonMark.blocks'),
                to_camel_case(self.tip.t))

        column_number = offset + 1
        new_block = Node(tag, [[self.line_number, column_number], [0, 0]])
        new_block.string_content = ''
        self.tip.append_child(new_block)
        self.tip = new_block
        return new_block
Beispiel #3
0
    def finalize(self, block, line_number):
        """ Finalize a block.  Close it and do any necessary postprocessing,
        e.g. creating string_content from strings, setting the 'tight'
        or 'loose' status of a list, and parsing the beginnings
        of paragraphs for reference definitions.  Reset the tip to the
        parent of the closed block."""
        above = block.parent
        block.is_open = False
        block.sourcepos[1] = [line_number, self.last_line_length]
        block_class = getattr(import_module('CommonMark.blocks'),
                              to_camel_case(block.t))
        block_class.finalize(self, block)

        self.tip = above
Beispiel #4
0
    def finalize(self, block, line_number):
        """ Finalize a block.  Close it and do any necessary postprocessing,
        e.g. creating string_content from strings, setting the 'tight'
        or 'loose' status of a list, and parsing the beginnings
        of paragraphs for reference definitions.  Reset the tip to the
        parent of the closed block."""
        above = block.parent
        block.is_open = False
        block.sourcepos[1] = [line_number, self.last_line_length]
        block_class = getattr(import_module('CommonMark.blocks'),
                              to_camel_case(block.t))
        block_class.finalize(self, block)

        self.tip = above
Beispiel #5
0
 def test_random_text(self, s):
     to_camel_case(s)
Beispiel #6
0
 def test_to_camel_case(self):
     self.assertEqual(to_camel_case('snake_case'), 'SnakeCase')
     self.assertEqual(to_camel_case(''), '')
     self.assertEqual(to_camel_case('word'), 'Word')
Beispiel #7
0
    def incorporate_line(self, ln):
        """Analyze a line of text and update the document appropriately.

        We parse markdown text by calling this on each line of input,
        then finalizing the document.
        """
        all_matched = True

        container = self.doc
        self.oldtip = self.tip
        self.offset = 0
        self.column = 0
        self.blank = False
        self.partially_consumed_tab = False
        self.line_number += 1

        # replace NUL characters for security
        if re.search(r'\u0000', ln) is not None:
            ln = re.sub(r'\0', '\uFFFD', ln)

        self.current_line = ln

        # For each containing block, try to parse the associated line start.
        # Bail out on failure: container will point to the last matching block.
        # Set all_matched to false if not all containers match.
        last_child = container.last_child
        while last_child and last_child.is_open:
            container = last_child

            self.find_next_nonspace()
            block_class = getattr(
                import_module('CommonMark.blocks'),
                to_camel_case(container.t))
            rv = block_class.continue_(self, container)
            if rv == 0:
                # we've matched, keep going
                pass
            elif rv == 1:
                # we've failed to match a block
                all_matched = False
            elif rv == 2:
                # we've hit end of line for fenced code close and can return
                self.last_line_length = len(ln)
                return
            else:
                raise ValueError('returned illegal value, must be 0, 1, or 2')

            if not all_matched:
                # back up to last matching block
                container = container.parent
                break

            last_child = container.last_child

        self.all_closed = (container == self.oldtip)
        self.last_matched_container = container

        block_class = getattr(import_module('CommonMark.blocks'),
                              to_camel_case(container.t))
        matched_leaf = container.t != 'paragraph' and block_class.accepts_lines
        starts = self.block_starts
        starts_len = len(starts.METHODS)
        # Unless last matched container is a code block, try new container
        # starts, adding children to the last matched container:
        while not matched_leaf:
            self.find_next_nonspace()

            # this is a little performance optimization:
            if not self.indented and \
               not re.search(reMaybeSpecial, ln[self.next_nonspace:]):
                self.advance_next_nonspace()
                break

            i = 0
            while i < starts_len:
                res = getattr(starts, starts.METHODS[i])(self, container)
                if res == 1:
                    container = self.tip
                    break
                elif res == 2:
                    container = self.tip
                    matched_leaf = True
                    break
                else:
                    i += 1

            if i == starts_len:
                # nothing matched
                self.advance_next_nonspace()
                break

        # What remains at the offset is a text line. Add the text to the
        # appropriate container.
        if not self.all_closed and not self.blank and \
           self.tip.t == 'paragraph':
            # lazy paragraph continuation
            self.add_line()
        else:
            # not a lazy continuation
            # finalize any blocks not matched
            self.close_unmatched_blocks()
            if self.blank and container.last_child:
                container.last_child.last_line_blank = True

            t = container.t

            # Block quote lines are never blank as they start with >
            # and we don't count blanks in fenced code for purposes of
            # tight/loose lists or breaking out of lists.  We also
            # don't set last_line_blank on an empty list item, or if we
            # just closed a fenced block.
            last_line_blank = self.blank and \
                not (t == 'block_quote' or
                     (t == 'code_block' and container.is_fenced) or
                     (t == 'item' and
                      not container.first_child and
                      container.sourcepos[0][0] == self.line_number))

            # propagate last_line_blank up through parents:
            cont = container
            while cont:
                cont.last_line_blank = last_line_blank
                cont = cont.parent

            block_class = getattr(import_module('CommonMark.blocks'),
                                  to_camel_case(t))
            if block_class.accepts_lines:
                self.add_line()
                # if HtmlBlock, check for end condition
                if t == 'html_block' and \
                   container.html_block_type >= 1 and \
                   container.html_block_type <= 5 and \
                   re.search(
                       reHtmlBlockClose[container.html_block_type],
                       self.current_line[self.offset:]):
                    self.finalize(container, self.line_number)
            elif self.offset < len(ln) and not self.blank:
                # create a paragraph container for one line
                container = self.add_child('paragraph', self.offset)
                self.advance_next_nonspace()
                self.add_line()

        self.last_line_length = len(ln)
Beispiel #8
0
    def incorporate_line(self, ln):
        """Analyze a line of text and update the document appropriately.

        We parse markdown text by calling this on each line of input,
        then finalizing the document.
        """
        all_matched = True

        container = self.doc
        self.oldtip = self.tip
        self.offset = 0
        self.column = 0
        self.blank = False
        self.partially_consumed_tab = False
        self.line_number += 1

        # replace NUL characters for security
        if re.search(r'\u0000', ln) is not None:
            ln = re.sub(r'\0', '\uFFFD', ln)

        self.current_line = ln

        # For each containing block, try to parse the associated line start.
        # Bail out on failure: container will point to the last matching block.
        # Set all_matched to false if not all containers match.
        last_child = container.last_child
        while last_child and last_child.is_open:
            container = last_child

            self.find_next_nonspace()
            block_class = getattr(
                import_module('CommonMark.blocks'),
                to_camel_case(container.t))
            rv = block_class.continue_(self, container)
            if rv == 0:
                # we've matched, keep going
                pass
            elif rv == 1:
                # we've failed to match a block
                all_matched = False
            elif rv == 2:
                # we've hit end of line for fenced code close and can return
                self.last_line_length = len(ln)
                return
            else:
                raise ValueError('returned illegal value, must be 0, 1, or 2')

            if not all_matched:
                # back up to last matching block
                container = container.parent
                break

            last_child = container.last_child

        self.all_closed = (container == self.oldtip)
        self.last_matched_container = container

        # Check to see if we've hit 2nd blank line; if so break out of list:
        if self.blank and container.last_line_blank:
            self.break_out_of_lists(container)
            container = self.tip

        block_class = getattr(import_module('CommonMark.blocks'),
                              to_camel_case(container.t))
        matched_leaf = container.t != 'paragraph' and block_class.accepts_lines
        starts = self.block_starts
        starts_len = len(starts.METHODS)
        # Unless last matched container is a code block, try new container
        # starts, adding children to the last matched container:
        while not matched_leaf:
            self.find_next_nonspace()

            # this is a little performance optimization:
            if not self.indented and \
               not re.search(reMaybeSpecial, ln[self.next_nonspace:]):
                self.advance_next_nonspace()
                break

            i = 0
            while i < starts_len:
                res = getattr(starts, starts.METHODS[i])(self, container)
                if res == 1:
                    container = self.tip
                    break
                elif res == 2:
                    container = self.tip
                    matched_leaf = True
                    break
                else:
                    i += 1

            if i == starts_len:
                # nothing matched
                self.advance_next_nonspace()
                break

        # What remains at the offset is a text line. Add the text to the
        # appropriate container.
        if not self.all_closed and not self.blank and \
           self.tip.t == 'paragraph':
            # lazy paragraph continuation
            self.add_line()
        else:
            # not a lazy continuation
            # finalize any blocks not matched
            self.close_unmatched_blocks()
            if self.blank and container.last_child:
                container.last_child.last_line_blank = True

            t = container.t

            # Block quote lines are never blank as they start with >
            # and we don't count blanks in fenced code for purposes of
            # tight/loose lists or breaking out of lists.  We also
            # don't set last_line_blank on an empty list item, or if we
            # just closed a fenced block.
            last_line_blank = self.blank and \
                not (t == 'block_quote' or
                     (t == 'code_block' and container.is_fenced) or
                     (t == 'item' and
                      not container.first_child and
                      container.sourcepos[0][0] == self.line_number))

            # propagate last_line_blank up through parents:
            cont = container
            while cont:
                cont.last_line_blank = last_line_blank
                cont = cont.parent

            block_class = getattr(import_module('CommonMark.blocks'),
                                  to_camel_case(t))
            if block_class.accepts_lines:
                self.add_line()
                # if HtmlBlock, check for end condition
                if t == 'html_block' and \
                   container.html_block_type >= 1 and \
                   container.html_block_type <= 5 and \
                   re.search(
                       reHtmlBlockClose[container.html_block_type],
                       self.current_line[self.offset:]):
                    self.finalize(container, self.line_number)
            elif self.offset < len(ln) and not self.blank:
                # create a paragraph container for one line
                container = self.add_child('paragraph', self.offset)
                self.advance_next_nonspace()
                self.add_line()

        self.last_line_length = len(ln)
Beispiel #9
0
 def test_to_camel_case(self):
     self.assertEqual(to_camel_case('snake_case'), 'SnakeCase')
     self.assertEqual(to_camel_case(''), '')
     self.assertEqual(to_camel_case('word'), 'Word')
 def test_random_text(self, s):
     to_camel_case(s)