Exemplo n.º 1
0
 def _handle_docstrings(self, block, lvl, prev_block):
     if block.docstring:
         is_start = block.text().strip().startswith('"""')
         if is_start:
             TextBlockHelper.get_fold_lvl(prev_block) + 1
         else:
             pblock = block.previous()
             while pblock.isValid() and pblock.text().strip() == '':
                 pblock = pblock.previous()
             is_start = pblock.text().strip().startswith('"""')
             if is_start:
                 return TextBlockHelper.get_fold_lvl(pblock) + 1
             else:
                 return TextBlockHelper.get_fold_lvl(pblock)
     # fix end of docstring
     elif prev_block and prev_block.text().strip().endswith('"""'):
         single_line = self._single_line_docstring.match(
             prev_block.text().strip())
         if single_line:
             TextBlockHelper.set_fold_lvl(prev_block, lvl)
         else:
             TextBlockHelper.set_fold_lvl(
                 prev_block, TextBlockHelper.get_fold_lvl(
                     prev_block.previous()))
     return lvl
Exemplo n.º 2
0
 def _handle_docstrings(self, block, lvl, prev_block):
     if block.docstring:
         is_start = block.text().strip().startswith('"""')
         if is_start:
             TextBlockHelper.get_fold_lvl(prev_block) + 1
         else:
             pblock = block.previous()
             while pblock.isValid() and pblock.text().strip() == '':
                 pblock = pblock.previous()
             is_start = pblock.text().strip().startswith('"""')
             if is_start:
                 return TextBlockHelper.get_fold_lvl(pblock) + 1
             else:
                 return TextBlockHelper.get_fold_lvl(pblock)
     # fix end of docstring
     elif prev_block and prev_block.text().strip().endswith('"""'):
         single_line = self._single_line_docstring.match(
             prev_block.text().strip())
         if single_line:
             TextBlockHelper.set_fold_lvl(prev_block, lvl)
         else:
             TextBlockHelper.set_fold_lvl(
                 prev_block,
                 TextBlockHelper.get_fold_lvl(prev_block.previous()))
     return lvl
Exemplo n.º 3
0
 def detect_fold_level(self, prev_block, block):
     if prev_block:
         prev_text = prev_block.text().strip()
     else:
         prev_text = ''
     if '[]' not in prev_text and '{}' not in prev_text:
         if prev_text.endswith(('{', '[')):
             return TextBlockHelper.get_fold_lvl(prev_block) + 1
         if prev_text.replace(',', '').endswith(('}', ']')):
             return TextBlockHelper.get_fold_lvl(prev_block) - 1
     return TextBlockHelper.get_fold_lvl(prev_block)
Exemplo n.º 4
0
 def collapse_all(self):
     """
     Collapses all triggers and makes all blocks with fold level > 0
     invisible.
     """
     self._clear_block_deco()
     block = self.editor.document().firstBlock()
     last = self.editor.document().lastBlock()
     while block.isValid():
         lvl = TextBlockHelper.get_fold_lvl(block)
         trigger = TextBlockHelper.is_fold_trigger(block)
         if trigger:
             if lvl == 0:
                 self._show_previous_blank_lines(block)
             TextBlockHelper.set_fold_trigger_state(block, True)
         block.setVisible(lvl == 0)
         if block == last and block.text().strip() == '':
             block.setVisible(True)
             self._show_previous_blank_lines(block)
         block = block.next()
     self._refresh_editor_and_scrollbars()
     tc = self.editor.textCursor()
     tc.movePosition(tc.Start)
     self.editor.setTextCursor(tc)
     self.collapse_all_triggered.emit()
Exemplo n.º 5
0
    def detect_fold_level(self, prev_block, block):
        ctext, ptext = self.stripped_texts(block, prev_block)
        if not self.editor.free_format:
            ctext = self.normalize_text(ctext)
            ptext = self.normalize_text(ptext)
        if regex.DIVISION.indexIn(
                ctext) != -1 and not ctext.lstrip().startswith('*'):
            return OFFSET_DIVISION
        elif regex.SECTION.indexIn(
                ctext) != -1 and not ctext.lstrip().startswith('*'):
            return OFFSET_SECTION
        else:
            # anywhere else, folding is mostly based on the indentation level
            indent = self.get_indent(ctext)
            pindent = self.get_indent(ptext)

            if ctext.strip().upper().startswith('END-') and self.is_valid(
                    prev_block) and pindent > indent:
                # find previous block with the same indent, use it's fold level + 1 to include
                # the end-branch statement in the fold scope
                pblock = prev_block
                while self.is_valid(pblock) and (pindent != indent
                                                 or len(ptext.strip()) == 0):
                    pblock = pblock.previous()
                    ptext = self.normalize_text(pblock.text())
                    pindent = self.get_indent(ptext)
                lvl = TextBlockHelper.get_fold_lvl(pblock.next())
            else:
                lvl = OFFSET_OTHER + indent

            # if not self.editor.free_format and (ctext.lstrip().startswith('-') or ctext.lstrip().startswith('*')):
            if not self.editor.free_format and (
                    ctext.lstrip().startswith('-')):
                # use previous fold level
                lvl = TextBlockHelper.get_fold_lvl(prev_block)

            if not self.editor.free_format and ctext.strip().startswith('*'):
                if regex.DIVISION.indexIn(
                        ptext) != -1 and not ptext.lstrip().startswith('*'):
                    lvl = OFFSET_SECTION
                elif regex.SECTION.indexIn(
                        ptext) != -1 and not ptext.lstrip().startswith('*'):
                    return OFFSET_SECTION + 2
                else:
                    lvl = TextBlockHelper.get_fold_lvl(prev_block)

            return lvl
Exemplo n.º 6
0
    def find_parent_scope(block):
        """
        Find parent scope, if the block is not a fold trigger.

        """
        original = block
        if not TextBlockHelper.is_fold_trigger(block):
            # search level of next non blank line
            while block.text().strip() == '' and block.isValid():
                block = block.next()
            ref_lvl = TextBlockHelper.get_fold_lvl(block) - 1
            block = original
            while (block.blockNumber() and
                   (not TextBlockHelper.is_fold_trigger(block) or
                    TextBlockHelper.get_fold_lvl(block) > ref_lvl)):
                block = block.previous()
        return block
Exemplo n.º 7
0
def test_fold_limit(editor):
    editor.syntax_highlighter.fold_detector.limit = 1
    editor.file.open('test/test_api/folding_cases/foo.py')
    block = editor.document().firstBlock()
    while block.blockNumber() < editor.blockCount() - 1:
        assert TextBlockHelper.get_fold_lvl(block) <= 1
        block = block.next()
    editor.syntax_highlighter.fold_detector.limit = sys.maxsize
Exemplo n.º 8
0
    def get_parent_scopes(block):
        """
        Gets the list of hierarchical parent scopes of the current block.

        :param block: current block
        :return: list of QTextBlock
        """
        scopes = [block]
        scope = FoldScope.find_parent_scope(block)
        while scope is not None:
            ref = TextBlockHelper.get_fold_lvl(scopes[-1])
            if TextBlockHelper.get_fold_lvl(scope) < ref:
                # ignore sibling scopes
                scopes.append(scope)
            if scope.blockNumber() == 0:
                # stop
                scope = None
            else:
                # next parent
                scope = FoldScope.find_parent_scope(scope.previous())
        return reversed(scopes)
Exemplo n.º 9
0
    def get_parent_scopes(block):
        """
        Gets the list of hierarchical parent scopes of the current block.

        :param block: current block
        :return: list of QTextBlock
        """
        scopes = [block]
        scope = FoldScope.find_parent_scope(block)
        while scope is not None:
            ref = TextBlockHelper.get_fold_lvl(scopes[-1])
            if TextBlockHelper.get_fold_lvl(scope) < ref:
                # ignore sibling scopes
                scopes.append(scope)
            if scope.blockNumber() == 0:
                # stop
                scope = None
            else:
                # next parent
                scope = FoldScope.find_parent_scope(scope.previous())
        return reversed(scopes)
Exemplo n.º 10
0
    def detect_fold_level(self, prev_block, block):
        ctext, ptext = self.stripped_texts(block, prev_block)
        if not self.editor.free_format:
            ctext = self.normalize_text(ctext)
            ptext = self.normalize_text(ptext)
        if regex.DIVISION.indexIn(ctext) != -1 and not ctext.lstrip().startswith('*'):
            return OFFSET_DIVISION
        elif regex.SECTION.indexIn(ctext) != -1 and not ctext.lstrip().startswith('*'):
            return OFFSET_SECTION
        else:
            # anywhere else, folding is mostly based on the indentation level
            indent = self.get_indent(ctext)
            pindent = self.get_indent(ptext)

            if ctext.strip().upper().startswith('END-') and self.is_valid(prev_block) and pindent > indent:
                # find previous block with the same indent, use it's fold level + 1 to include
                # the end-branch statement in the fold scope
                pblock = prev_block
                while self.is_valid(pblock) and (pindent != indent or len(ptext.strip()) == 0):
                    pblock = pblock.previous()
                    ptext = self.normalize_text(pblock.text())
                    pindent = self.get_indent(ptext)
                lvl = TextBlockHelper.get_fold_lvl(pblock.next())
            else:
                lvl = OFFSET_OTHER + indent

            # if not self.editor.free_format and (ctext.lstrip().startswith('-') or ctext.lstrip().startswith('*')):
            if not self.editor.free_format and (ctext.lstrip().startswith('-')):
                # use previous fold level
                lvl = TextBlockHelper.get_fold_lvl(prev_block)

            if not self.editor.free_format and ctext.strip().startswith('*'):
                if regex.DIVISION.indexIn(ptext) != -1 and not ptext.lstrip().startswith('*'):
                    lvl = OFFSET_SECTION
                elif regex.SECTION.indexIn(ptext) != -1 and not ptext.lstrip().startswith('*'):
                    return OFFSET_SECTION + 2
                else:
                    lvl = TextBlockHelper.get_fold_lvl(prev_block)

            return lvl
Exemplo n.º 11
0
def test_collapse_all(editor):
    panel = get_panel(editor)
    QTest.qWait(1000)
    panel.collapse_all()
    QTest.qWait(1000)
    block = editor.document().firstBlock()
    while block.blockNumber() < editor.document().blockCount() - 1:
        blank_line = len(block.text().strip()) == 0
        if TextBlockHelper.get_fold_lvl(block) > 0:
            if not blank_line:
                assert block.isVisible() is False
        else:
            assert block.isVisible() is True
        if TextBlockHelper.is_fold_trigger(block):
            assert TextBlockHelper.is_collapsed(block) is True
        block = block.next()
Exemplo n.º 12
0
    def detect_fold_level(self, prev_block, block):
        """
        Perfoms fold level detection for current block (take previous block
        into account).

        :param prev_block: previous block, None if `block` is the first block.
        :param block: block to analyse.
        :return: block fold level
        """
        # Python is an indent based language so use indentation for folding
        # makes sense but we restrict new regions to indentation after a ':',
        # that way only the real logical blocks are displayed.
        lvl = super(PythonFoldDetector, self).detect_fold_level(
            prev_block, block)
        # cancel false indentation, indentation can only happen if there is
        # ':' on the previous line
        prev_lvl = TextBlockHelper.get_fold_lvl(prev_block)
        if prev_block and lvl > prev_lvl and not (
                self._strip_comments(prev_block).endswith(':')):
            lvl = prev_lvl
        lvl = self._handle_docstrings(block, lvl, prev_block)
        lvl = self._handle_imports(block, lvl, prev_block)
        return lvl
Exemplo n.º 13
0
    def detect_fold_level(self, prev_block, block):
        """
        Perfoms fold level detection for current block (take previous block
        into account).

        :param prev_block: previous block, None if `block` is the first block.
        :param block: block to analyse.
        :return: block fold level
        """
        # Python is an indent based language so use indentation for folding
        # makes sense but we restrict new regions to indentation after a ':',
        # that way only the real logical blocks are displayed.
        lvl = super(PythonFoldDetector,
                    self).detect_fold_level(prev_block, block)
        # cancel false indentation, indentation can only happen if there is
        # ':' on the previous line
        prev_lvl = TextBlockHelper.get_fold_lvl(prev_block)
        if prev_block and lvl > prev_lvl and not (
                self._strip_comments(prev_block).endswith(':')):
            lvl = prev_lvl
        lvl = self._handle_docstrings(block, lvl, prev_block)
        lvl = self._handle_imports(block, lvl, prev_block)
        return lvl
Exemplo n.º 14
0
 def detect_fold_level(self, prev_block, block):
     if not prev_block:
         return 0
     ctext, ptext = self.stripped_texts(block, prev_block)
     if ctext.endswith('DIVISION.'):
         if 'DATA' in ctext:
             self.data_division = block
             self._data_div_txt = block.text()
         if 'PROCEDURE' in ctext:
             self.proc_division = block
             self._proc_div_txt = block.text()
         return 0
     elif ctext.endswith('SECTION.'):
         return 1
     elif ptext.endswith('DIVISION.'):
         return 1
     elif ptext.endswith('SECTION.'):
         return 2
     # in case of replace all or simply if the user deleted the data or
     # proc div.
     if (self.proc_division and
             self.proc_division.text() != self._proc_div_txt):
         self.proc_division = None
     if (self.data_division and
             self.data_division.text() != self._data_div_txt):
         self.data_division = None
     # inside PROCEDURE DIVISION
     if (self.proc_division and self.proc_division.isValid() and
             block.blockNumber() > self.proc_division.blockNumber()):
         # we only detect outline of paragraphes
         if regex.PARAGRAPH_PATTERN.indexIn(block.text()) != -1:
             # paragraph
             return 1
         else:
             # content of a paragraph
             if regex.PARAGRAPH_PATTERN.indexIn(prev_block.text()) != -1:
                 return 2
             else:
                 cstxt = ctext.lstrip()
                 pstxt = ptext.lstrip()
                 plvl = TextBlockHelper.get_fold_lvl(prev_block)
                 if regex.LOOP_PATTERN.indexIn(pstxt) != -1:
                     pstxt = '$L$O$OP$'
                 if pstxt in ['END-IF', 'END-PERFORM', 'END-READ']:
                     if cstxt in ['ELSE']:
                         return plvl - 2
                     return plvl - 1
                 if cstxt in ['ELSE']:
                     return plvl - 1
                 for token in ['IF', 'ELSE', '$L$O$OP$', 'READ']:
                     if pstxt.startswith(token):
                         return plvl + 1
                 return plvl
     # INSIDE  DATA DIVISION
     elif (self.data_division and self.data_division.isValid() and
             block.blockNumber() > self.data_division.blockNumber() + 1):
         # here folding is based on the indentation level
         offset = 6
         indent = ((len(ctext) - len(ctext.lstrip()) - offset) //
                   self.editor.tab_length)
         return 2 + indent
     # other lines follow their previous fold level
     plvl = TextBlockHelper.get_fold_lvl(prev_block)
     return plvl