def process_block(self, current_block, previous_block, text): """ Processes a block and setup its folding info. This method call ``detect_fold_level`` and handles most of the tricky corner cases so that all you have to do is focus on getting the proper fold level foreach meaningful block, skipping the blank ones. :param current_block: current block to process :param previous_block: previous block :param text: current block text """ prev_fold_level = TextBlockHelper.get_fold_lvl(previous_block) if text.strip() == '' or self.editor.is_comment(current_block): # blank or comment line always have the same level # as the previous line fold_level = prev_fold_level else: fold_level = self.detect_fold_level( previous_block, current_block) if fold_level > self.limit: fold_level = self.limit prev_fold_level = TextBlockHelper.get_fold_lvl(previous_block) if fold_level > prev_fold_level: # apply on previous blank or comment lines block = current_block.previous() while block.isValid() and (block.text().strip() == '' or self.editor.is_comment(block)): TextBlockHelper.set_fold_lvl(block, fold_level) block = block.previous() TextBlockHelper.set_fold_trigger( block, True) # update block fold level if text.strip() and not self.editor.is_comment(previous_block): TextBlockHelper.set_fold_trigger( previous_block, fold_level > prev_fold_level) TextBlockHelper.set_fold_lvl(current_block, fold_level) # user pressed enter at the beginning of a fold trigger line # the previous blank or comment line will keep the trigger state # and the new line (which actually contains the trigger) must use # the prev state (and prev state must then be reset). prev = current_block.previous() # real prev block (may be blank) if (prev and prev.isValid() and (prev.text().strip() == '' or self.editor.is_comment(prev)) and TextBlockHelper.is_fold_trigger(prev)): # prev line has the correct trigger fold state TextBlockHelper.set_collapsed( current_block, TextBlockHelper.is_collapsed( prev)) # make empty or comment line not a trigger TextBlockHelper.set_fold_trigger(prev, False) TextBlockHelper.set_collapsed(prev, False)
class TestFoldScopeHelper(object): test_case = """# -*- coding: utf-8 -*- def my_add(): a = 1 b = 2 return a + b """ doc = QTextDocument(test_case) sh = PythonSH(doc, color_scheme='Spyder') sh.fold_detector = IndentFoldDetector() sh.rehighlightBlock(doc.firstBlock()) block = doc.firstBlock() block = block.next() TextBlockHelper.set_fold_trigger(block, True) fold_scope = FoldScope(block) oed = block.userData().oedata def test_fold_scope_helper(self): fsh = cfd.FoldScopeHelper(None, None) assert isinstance(fsh, cfd.FoldScopeHelper) def test_fold_scope_helper_str(self): fsh = cfd.FoldScopeHelper(self.fold_scope, self.oed) assert "my_add" in str(fsh) def test_fold_scope_helper_str_with_parents(self): fsh = cfd.FoldScopeHelper(self.fold_scope, self.oed) fsh.parents = ["fake parent list!"] assert "parents:" in str(fsh) def test_fold_scope_helper_repr(self): fsh = cfd.FoldScopeHelper(self.fold_scope, self.oed) assert "(at 0x" in repr(fsh) def test_fold_scope_helper_properties(self): fsh = cfd.FoldScopeHelper(self.fold_scope, self.oed) assert fsh.range == (1, 4) assert fsh.start_line == 1 assert fsh.end_line == 4 assert fsh.name == "my_add" assert fsh.line == 1 assert fsh.def_type == OED.FUNCTION_TOKEN