Repository: spyder-ide/spyder

Issue:
Code folding disabled w/ <2000 lines (4.1.1)
[demo](https://puu.sh/Fmns3/ccc8ec6539.mp4); release notes state it should only happen for files w/ >2000 lines (which hopefully won't be needed in a future version) - but folding's disabled for 300-liners also.

_Note_: also occurs in 4.1


Discussion:
You're right. I don't understand how we miss this one. We'll fix it in 4.1.2.

Resolving patch:
diff --git a/spyder/config/main.py b/spyder/config/main.py
--- a/spyder/config/main.py
+++ b/spyder/config/main.py
@@ -195,7 +195,7 @@
               'edge_line_columns': '79',
               'indent_guides': False,
               'code_folding': True,
-              'code_folding_warn': True,
+              'show_code_folding_warning': True,
               'scroll_past_end': False,
               'toolbox_panel': True,
               'close_parentheses': True,
@@ -624,4 +624,4 @@
 #    or if you want to *rename* options, then you need to do a MAJOR update in
 #    version, e.g. from 3.0.0 to 4.0.0
 # 3. You don't need to touch this value if you're just adding a new option
-CONF_VERSION = '56.0.0'
+CONF_VERSION = '57.0.0'
diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py
--- a/spyder/plugins/editor/widgets/codeeditor.py
+++ b/spyder/plugins/editor/widgets/codeeditor.py
@@ -88,6 +88,7 @@
                                     mimedata2url)
 from spyder.utils.vcs import get_git_remotes, remote_to_url
 from spyder.utils.qstringhelpers import qstring_length
+from spyder.widgets.helperwidgets import MessageCheckBox
 
 
 try:
@@ -1394,15 +1395,27 @@ def request_folding(self):
         """Request folding."""
         total_lines = self.get_line_count()
         if total_lines > 2000 and self.code_folding:
-            warn = CONF.get('editor', 'code_folding_warn')
-            warn_str = _("This file contains more than 2000 lines!  "
-                         "Code folding and indent guidelines will be  "
-                         "disabled in order to prevent performance "
-                         "degradation.")
+            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:
-                QMessageBox.information(self, _('File too long'), warn_str,
-                                        QMessageBox.Ok)
-                CONF.set('editor', 'code_folding_warn', False)
+                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)
 
@@ -1519,11 +1532,8 @@ def toggle_code_folding(self, state):
             self.code_folding = True
 
     def toggle_identation_guides(self, state):
-        folding_panel = self.panels.get(FoldingPanel)
         if state and not self.code_folding:
             self.code_folding = True
-        elif not state and not folding_panel.isVisible():
-            self.code_folding = False
         self.indent_guides.set_enabled(state)
 
     def toggle_completions_hint(self, state):


Test patch:
diff --git a/spyder/plugins/editor/widgets/tests/test_classfunc_selector.py b/spyder/plugins/editor/widgets/tests/test_classfunc_selector.py
--- a/spyder/plugins/editor/widgets/tests/test_classfunc_selector.py
+++ b/spyder/plugins/editor/widgets/tests/test_classfunc_selector.py
@@ -54,9 +54,15 @@ def test_class_func_selector(lsp_codeeditor, qtbot):
     with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
         code_editor.document_did_change()
 
+    # Wait a little bit before asking for symbols
+    qtbot.wait(2000)
+
     with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
         code_editor.request_symbols()
 
+    # Wait for symbols info to arrive
+    qtbot.wait(2000)
+
     class_names = [item['name'] for item in panel.classes]
     func_names = [item['name'] for item in panel.funcs]
 
diff --git a/spyder/plugins/editor/widgets/tests/test_folding.py b/spyder/plugins/editor/widgets/tests/test_folding.py
--- a/spyder/plugins/editor/widgets/tests/test_folding.py
+++ b/spyder/plugins/editor/widgets/tests/test_folding.py
@@ -63,14 +63,17 @@ def test_folding(lsp_codeeditor, qtbot):
     code_editor, _ = lsp_codeeditor
     code_editor.toggle_code_folding(True)
     code_editor.insert_text(text)
+    folding_panel = code_editor.panels.get('FoldingPanel')
 
     with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
         code_editor.document_did_change()
 
-    with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
-        code_editor.request_folding()
+    while folding_panel.folding_regions == {}:
+        # This fixes the race condition on the PyLS with the
+        # document_did_change() event
+        with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+            code_editor.request_folding()
 
-    folding_panel = code_editor.panels.get('FoldingPanel')
     folding_regions = folding_panel.folding_regions
     folding_levels = folding_panel.folding_levels
 
@@ -97,8 +100,11 @@ def test_unfold_when_searching(search_codeeditor, qtbot):
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
-    with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
-        editor.request_folding()
+    while folding_panel.folding_regions == {}:
+        # This fixes the race condition on the PyLS with the
+        # document_did_change() event
+        with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+            editor.request_folding()
 
     line_search = editor.document().findBlockByLineNumber(3)
 
@@ -123,14 +129,17 @@ def test_unfold_goto(search_codeeditor, qtbot):
     editor, finder = search_codeeditor
     editor.toggle_code_folding(True)
     editor.insert_text(text)
+    folding_panel = editor.panels.get('FoldingPanel')
 
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
-    with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
-        editor.request_folding()
+    while folding_panel.folding_regions == {}:
+        # This fixes the race condition on the PyLS with the
+        # document_did_change() event
+        with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+            editor.request_folding()
 
-    folding_panel = editor.panels.get('FoldingPanel')
     line_goto = editor.document().findBlockByLineNumber(5)
 
     # fold region
diff --git a/spyder/plugins/editor/widgets/tests/test_warnings.py b/spyder/plugins/editor/widgets/tests/test_warnings.py
--- a/spyder/plugins/editor/widgets/tests/test_warnings.py
+++ b/spyder/plugins/editor/widgets/tests/test_warnings.py
@@ -116,6 +116,9 @@ def test_move_warnings(qtbot, lsp_codeeditor):
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
+    # Wait for linting info to arrive
+    qtbot.wait(2000)
+
     # Move between warnings
     editor.go_to_next_warning()
     assert 2 == editor.get_cursor_line_number()
@@ -149,6 +152,9 @@ def test_get_warnings(qtbot, lsp_codeeditor):
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
+    # Wait for linting info to arrive
+    qtbot.wait(2000)
+
     # Get current warnings
     warnings = editor.get_current_warnings()
 
@@ -182,6 +188,9 @@ def test_update_warnings_after_delete_line(qtbot, lsp_codeeditor):
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
+    # Wait for linting info to arrive
+    qtbot.wait(2000)
+
     # Delete the blank line that is causing the W293 warning on line 2.
     editor.go_to_line(2)
     editor.delete_line()
@@ -220,6 +229,9 @@ def test_update_warnings_after_closequotes(qtbot, lsp_codeeditor):
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
+    # Wait for linting info to arrive
+    qtbot.wait(2000)
+
     assert editor.get_current_warnings() == expected
 
     # Wait for the lsp_response_signal.
@@ -254,6 +266,9 @@ def test_update_warnings_after_closebrackets(qtbot, lsp_codeeditor):
     with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
         editor.document_did_change()
 
+    # Wait for linting info to arrive
+    qtbot.wait(2000)
+
     assert editor.get_current_warnings() == expected
 
     # Wait for the lsp_response_signal.