Repository: spyder-ide/spyder
Pull request: PR: Enable/disable folding guides when cursor enters/exits the left panel
<!--- Make sure to read the Contributing Guidelines:                   --->
<!--- https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md --->
<!--- and follow PEP 8, PEP 257 and Spyder's code style:               --->
<!--- https://github.com/spyder-ide/spyder/wiki/Dev:-Coding-Style      --->

## Description of Changes
This PR disables folding guides visibility by default, instead, they will be shown only if the cursor enters the left panel and disabled when the cursor leaves it. We also re-enable the folding support for large files that was disabled previously. 

* [ ] Wrote at least one-line docstrings (for any new functions)
* [ ] Added unit test(s) covering the changes (if testable)
<!--- Remember that an image/animation is worth a thousand words! --->
* [x] Included a screenshot or animation (if affecting the UI, see [Licecap](https://www.cockos.com/licecap/))

![Peek 02-06-2020 14-39](https://user-images.githubusercontent.com/1878982/83562436-2d20ad80-a4df-11ea-9971-3a13ae0c510c.gif)

<!--- Explain what you've done and why --->




### Issue(s) Resolved

<!--- List the issue(s) below, in the form "Fixes #1234"; one per line --->

Fixes #12315.


### Affirmation

By submitting this Pull Request or typing my (user)name below,
I affirm the [Developer Certificate of Origin](https://developercertificate.org)
with respect to all commits and content included in this PR,
and understand I am releasing the same under Spyder's MIT (Expat) license.

<!--- TYPE YOUR USER/NAME AFTER THE FOLLOWING: --->
I certify the above statement is true and correct: @andfoy 

<!--- Thanks for your help making Spyder better for everyone! --->


Problem statement:
Restore code folding for large files
In order to do that we need to do the following:

* Only draw and update the folding panel when the user moves the cursor over it.
* Only draw the visible region in the editor (although that's probably not so necessary if we draw the panel on demand).

@andfoy, please take a look at this one.

Hints from issue discussion:

Commit message: Fix style issues

Patch to review:
diff --git a/spyder/plugins/editor/panels/codefolding.py b/spyder/plugins/editor/panels/codefolding.py
index 58ffb823442..ef252387cd3 100644
--- a/spyder/plugins/editor/panels/codefolding.py
+++ b/spyder/plugins/editor/panels/codefolding.py
@@ -168,6 +168,8 @@ def __init__(self, highlight_caret_scope=False):
         self.action_collapse_all = None
         self.action_expand_all = None
         self._original_background = None
+        self._display_folding = False
+        self._key_pressed = False
         self._highlight_runner = DelayJobRunner(delay=250)
         self.folding_regions = {}
         self.folding_status = {}
@@ -248,6 +250,28 @@ def paintEvent(self, event):
         # on the folding panel.
         super(FoldingPanel, self).paintEvent(event)
         painter = QPainter(self)
+        if not self._display_folding and not self._key_pressed:
+            if any(self.folding_status.values()):
+                for info in self.editor.visible_blocks:
+                    top_position, line_number, block = info
+                    if line_number in self.folding_regions:
+                        collapsed = self.folding_status[line_number]
+                        line_end = self.folding_regions[line_number]
+                        mouse_over = self._mouse_over_line == line_number
+                        if collapsed:
+                            self._draw_fold_indicator(
+                                top_position, mouse_over, collapsed, painter)
+                            # check if the block already has a decoration,
+                            # it might have been folded by the parent
+                            # editor/document in the case of cloned editor
+                            for deco in self._block_decos:
+                                if deco.block == block:
+                                    # no need to add a deco, just go to the
+                                    # next block
+                                    break
+                            else:
+                                self._add_fold_decoration(block, line_end)
+            return
         # Draw background over the selected non collapsed fold region
         if self._mouse_over_line is not None:
             block = self.editor.document().findBlockByNumber(
@@ -503,6 +527,10 @@ def mouseMoveEvent(self, event):
                 QApplication.restoreOverrideCursor()
             self.repaint()
 
+    def enterEvent(self, event):
+        self._display_folding = True
+        self.repaint()
+
     def leaveEvent(self, event):
         """
         Removes scope decorations and background from the editor and the panel
@@ -520,6 +548,7 @@ def leaveEvent(self, event):
             self._block_nbr = -1
             self._highlight_caret_scope()
         self.editor.repaint()
+        self._display_folding = False
 
     def _add_fold_decoration(self, block, end_line):
         """
@@ -631,6 +660,7 @@ def _on_key_pressed(self, event):
                                          Qt.Key_Delete]
         if event.text() or delete_request:
             cursor = self.editor.textCursor()
+            self._key_pressed = True
             if cursor.hasSelection():
                 # change selection to encompass the whole scope.
                 positions_to_check = cursor.selectionStart(), cursor.selectionEnd()
@@ -658,6 +688,7 @@ def _on_key_pressed(self, event):
                         self.editor.setTextCursor(tc)
                         self.folding_regions.pop(start_line)
                         self.folding_status.pop(start_line)
+            self._key_pressed = False
 
     @staticmethod
     def _show_previous_blank_lines(block):
diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py
index 098d989e4a1..9e2b82f17f2 100644
--- a/spyder/plugins/editor/widgets/codeeditor.py
+++ b/spyder/plugins/editor/widgets/codeeditor.py
@@ -1472,32 +1472,6 @@ def compute_whitespace(line):
     @request(method=LSPRequestTypes.DOCUMENT_FOLDING_RANGE)
     def request_folding(self):
         """Request folding."""
-        total_lines = self.get_line_count()
-        if total_lines > 2000 and self.code_folding:
-            warn = CONF.get('editor', 'show_code_folding_warning')
-            warn_str = _(
-                "One of the files in the editor or the file you are trying "
-                "to open contains more than 2000 lines.<br><br>"
-                "Code folding and indent guidelines will be disabled for "
-                "this kind of files in order to prevent performance "
-                "degradation."
-            )
-            if warn:
-                box = MessageCheckBox(
-                    icon=QMessageBox.Warning, parent=self)
-                box.setWindowTitle(_('File too long'))
-                box.set_checkbox_text(_("Don't show again."))
-                box.setStandardButtons(QMessageBox.Ok)
-                box.set_checked(False)
-                box.set_check_visible(True)
-                box.setText(warn_str)
-                box.exec_()
-
-                CONF.set('editor', 'show_code_folding_warning',
-                         not box.is_checked())
-            self.toggle_code_folding(False)
-            self.toggle_identation_guides(False)
-
         if not self.folding_supported or not self.code_folding:
             return
         params = {'file': self.filename}


Code review comments:
diff_hunk: @@ -248,6 +250,28 @@ def paintEvent(self, event):
         # on the folding panel.
         super(FoldingPanel, self).paintEvent(event)
         painter = QPainter(self)
+        if not self._display_folding and not self._key_pressed:
+            if any(self.folding_status.values()):
+                for info in self.editor.visible_blocks:
+                    top_position, line_number, block = info
+                    if line_number in self.folding_regions:
+                        collapsed = self.folding_status[line_number]
+                        line_end = self.folding_regions[line_number]
+                        mouse_over = self._mouse_over_line == line_number
+                        if collapsed:
+                            self._draw_fold_indicator(
+                                top_position, mouse_over, collapsed, painter)
+                            # check if the block already has a decoration,
+                            # it might have been folded by the parent
+                            # editor/document in the case of cloned editor
+                            for deco in self._block_decos:
+                                if deco.block == block:
+                                    # no need to add a deco, just go to the
+                                    # next block
+                                    break
+                            else:
+                                self._add_fold_decoration(block, line_end)
+            return
path: spyder/plugins/editor/panels/codefolding.py
text: @user1:
The code you added in these lines is very, very similar to the code to draw fold triggers from like 10 lines below. Do you see a way to refactor both and have a single method here and there?