Repository: spyder-ide/spyder

Issue:
Allow setting line length, when setting `black` as autoformatter
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

## Problem Description

When setting `black` as autoformatter, the line-length (and the vertical ruler) are set and fixed to `88`.
Related: #14082

### What steps reproduce the problem?

1. set `Preferences` -> `Completion and linting` -> `Code formatting` -> `Choose the code formatting provider` to `black`
2. `Preferences` -> `Completion and linting` -> `Code style` -> `Maximum allowed line length` is auto. set to `88`
3. can't change this `Maximum allowed line length`

### What is the expected output? What do you see instead?
Preset of `88` for `black` is fine, but since `black` provides the `-l` option ([link](https://github.com/psf/black#command-line-options)), the maximum line length should be changeable. 

## Versions
* Spyder version: 4.2.0

### Dependencies
* black


Discussion:
Hi @MuellerSeb,

Black has a default of 88 for the maximum line length, so we decided to change those options automatically in case of choosing black as the autoformatter. If you want to preserve the 79 option, please change those options manually in `Preferences > Completion and linting > Code style > Maximum allowed line length`

Please let me know if this works
Hey @steff456,
when I type e.g. 79 there and click apply, it just snaps back to 88. So I consider this a bug.
You are right! I can reproduce it, we will work in fixing it :)
@steff456, I think the solution to this is to move the `Maximum allowed length` option out of the group `Enable code style linting`, so that users don't require to activate that just to change it:

![Selección_024](https://user-images.githubusercontent.com/365293/98733894-399f1100-236f-11eb-8495-a2508fab0809.png)

Besides, we need to remove the validations we added to automatically set that value according to the auto-formatter currently selected. Instead, we need to let users pick out that value freely.

Resolving patch:
diff --git a/spyder/plugins/completion/languageserver/confpage.py b/spyder/plugins/completion/languageserver/confpage.py
--- a/spyder/plugins/completion/languageserver/confpage.py
+++ b/spyder/plugins/completion/languageserver/confpage.py
@@ -169,7 +169,7 @@ def setup_page(self):
 
         linting_check.toggled.connect(underline_errors_box.setEnabled)
 
-        # --- Code style tab ---
+        # --- Code style and formatting tab ---
         # Code style label
         pep_url = (
             '<a href="https://www.python.org/dev/peps/pep-0008">PEP 8</a>')
@@ -213,7 +213,7 @@ def setup_page(self):
             tip=_("Default is 79"))
 
         vertical_line_box = newcb(
-            _("Show vertical line at maximum allowed length"), 'edge_line',
+            _("Show vertical line at that length"), 'edge_line',
             section='editor')
 
         # Code style layout
@@ -228,10 +228,6 @@ def setup_page(self):
         code_style_g_layout.addWidget(code_style_select.textbox, 3, 1)
         code_style_g_layout.addWidget(code_style_ignore.label, 4, 0)
         code_style_g_layout.addWidget(code_style_ignore.textbox, 4, 1)
-        code_style_g_layout.addWidget(
-            self.code_style_max_line_length.plabel, 5, 0)
-        code_style_g_layout.addWidget(
-            self.code_style_max_line_length.spinbox, 5, 1)
 
         # Set Code style options enabled/disabled
         code_style_g_widget = QWidget()
@@ -240,16 +236,20 @@ def setup_page(self):
         self.code_style_check.toggled.connect(code_style_g_widget.setEnabled)
 
         # Code style layout
+        code_style_group = QGroupBox(_("Code style"))
         code_style_layout = QVBoxLayout()
         code_style_layout.addWidget(code_style_label)
         code_style_layout.addWidget(self.code_style_check)
         code_style_layout.addWidget(code_style_g_widget)
-        code_style_layout.addWidget(vertical_line_box)
+        code_style_group.setLayout(code_style_layout)
 
-        code_style_widget = QWidget()
-        code_style_widget.setLayout(code_style_layout)
+        # Maximum allowed line length layout
+        line_length_group = QGroupBox(_("Line length"))
+        line_length_layout = QVBoxLayout()
+        line_length_layout.addWidget(self.code_style_max_line_length)
+        line_length_layout.addWidget(vertical_line_box)
+        line_length_group.setLayout(line_length_layout)
 
-        # --- Code formatting tab ---
         # Code formatting label
         autopep8_url = (
             "<a href='https://github.com/hhatto/autopep8'>Autopep8</a>"
@@ -282,13 +282,19 @@ def setup_page(self):
                   "saving a file"))
 
         # Code formatting layout
+        code_fmt_group = QGroupBox(_("Code formatting"))
         code_fmt_layout = QVBoxLayout()
         code_fmt_layout.addWidget(code_fmt_label)
         code_fmt_layout.addWidget(code_fmt_provider)
         code_fmt_layout.addWidget(format_on_save_box)
+        code_fmt_group.setLayout(code_fmt_layout)
 
-        code_fmt_widget = QWidget()
-        code_fmt_widget.setLayout(code_fmt_layout)
+        code_style_widget = QWidget()
+        code_style_fmt_layout = QVBoxLayout()
+        code_style_fmt_layout.addWidget(code_style_group)
+        code_style_fmt_layout.addWidget(code_fmt_group)
+        code_style_fmt_layout.addWidget(line_length_group)
+        code_style_widget.setLayout(code_style_fmt_layout)
 
         # --- Docstring tab ---
         # Docstring style label
@@ -623,11 +629,10 @@ def setup_page(self):
         self.tabs.addTab(self.create_tab(linting_widget), _('Linting'))
         self.tabs.addTab(self.create_tab(introspection_group, advanced_group),
                          _('Introspection'))
-        self.tabs.addTab(self.create_tab(code_style_widget), _('Code style'))
+        self.tabs.addTab(self.create_tab(code_style_widget),
+                         _('Code style and formatting'))
         self.tabs.addTab(self.create_tab(docstring_style_widget),
                          _('Docstring style'))
-        self.tabs.addTab(self.create_tab(code_fmt_widget),
-                         _('Code formatting'))
         self.tabs.addTab(self.create_tab(snippets_widget), _('Snippets'))
         self.tabs.addTab(self.create_tab(clients_group,
                                          lsp_advanced_group,
@@ -938,16 +943,6 @@ def apply_settings(self, options):
         self.table.save_servers()
         self.snippets_proxy.save_snippets()
 
-        if(self.get_option('formatting') == 'black' and
-                self.get_option('pycodestyle/max_line_length') == 79):
-            self.set_option('pycodestyle/max_line_length', 88)
-            self.code_style_max_line_length.spinbox.setValue(88)
-
-        if(self.get_option('formatting') != 'black' and
-                self.get_option('pycodestyle/max_line_length') == 88):
-            self.set_option('pycodestyle/max_line_length', 79)
-            self.code_style_max_line_length.spinbox.setValue(79)
-
         # Update entries in the source menu
         for name, action in self.main.editor.checkable_actions.items():
             if name in options:


Test patch:
diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py
--- a/spyder/app/tests/test_mainwindow.py
+++ b/spyder/app/tests/test_mainwindow.py
@@ -2420,7 +2420,7 @@ def test_preferences_checkboxes_not_checked_regression(main_window, qtbot):
     # Get the correct tab pages inside the Completion preferences page
     tnames = [page.tabs.tabText(i).lower() for i in range(page.tabs.count())]
     tab_widgets = {
-        tnames.index('code style'): page.code_style_check,
+        tnames.index('code style and formatting'): page.code_style_check,
         tnames.index('docstring style'): page.docstring_style_check,
     }
     for idx, check in tab_widgets.items():