Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Fix applying configuration options to the editor #16906

Merged
merged 6 commits into from
Nov 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions spyder/api/config/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

# Standard library imports
import functools
from typing import Callable, Type, Any, Optional, Union, List
import inspect
from typing import Callable, Optional, Union, List

# Local imports
from spyder.config.types import ConfigurationKey
Expand Down
5 changes: 1 addition & 4 deletions spyder/api/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@

# Standard library imports
import types
from typing import Tuple, Union, Set

# Third party imports
from qtpy.QtWidgets import QWidget
from typing import Set

# Local imports
from spyder.config.manager import CONF
Expand Down
54 changes: 6 additions & 48 deletions spyder/plugins/completion/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@
"""

# Standard library imports
from collections import defaultdict
import functools
import inspect
import logging
import os
from pkg_resources import parse_version, iter_entry_points
from typing import List, Any, Union, Optional, Tuple
from typing import List, Union

# Third-party imports
from qtpy.QtCore import QMutex, QMutexLocker, QTimer, Slot, Signal
from qtpy.QtWidgets import QMessageBox

# Local imports
from spyder.config.manager import CONF
Expand Down Expand Up @@ -388,8 +386,11 @@ def after_configuration_update(self, options: List[Union[tuple, str]]):
provider tabs.
"""
providers_to_update = set({})
options = [x[1] if isinstance(x, tuple) and
len(x) == 2 and x[0] is None else x for x in options]
options = [
x[1] if isinstance(x, tuple) and
len(x) == 2 and x[0] is None or 'editor'
else x for x in options
]
for option in options:
if option == 'completions_wait_for_ms':
self.wait_for_ms = self.get_conf(
Expand All @@ -408,49 +409,6 @@ def after_configuration_update(self, options: List[Union[tuple, str]]):
elif option_name == 'provider_configuration':
providers_to_update |= {provider_name}

# FIXME: Remove this after migrating the ConfManager to an observer
# pattern.
editor_method_sec_opts = {
'set_code_snippets_enabled': (self.CONF_SECTION,
'enable_code_snippets'),
'set_hover_hints_enabled': (self.CONF_SECTION,
'provider_configuration',
'lsp',
'values',
'enable_hover_hints'),
'set_format_on_save': (self.CONF_SECTION,
'provider_configuration',
'lsp',
'values',
'format_on_save'),
'set_automatic_completions_enabled': ('editor',
'automatic_completions'),
'set_completions_hint_enabled': ('editor', 'completions_hint'),
'set_completions_hint_after_ms': ('editor',
'completions_hint_after_ms'),
'set_underline_errors_enabled': ('editor', 'underline_errors'),
'set_automatic_completions_after_chars': (
'editor', 'automatic_completions_after_chars'),
'set_automatic_completions_after_ms': (
'editor', 'automatic_completions_after_ms'),
'set_edgeline_columns': (self.CONF_SECTION,
'provider_configuration',
'lsp',
'values',
'pycodestyle/max_line_length'),
'set_edgeline_enabled': ('editor', 'edge_line'),
}

for method_name, (sec, *opt) in editor_method_sec_opts.items():
opt = tuple(opt)
if len(opt) == 1:
opt = opt[0]
if opt in options:
opt_value = self.get_conf(opt, section=sec)
self.sig_editor_rpc.emit('call_all_editorstacks',
(method_name, (opt_value,),),
{})

# Update entries in the source menu
# FIXME: Delete this after CONF is moved to an observer pattern.
# and the editor migration starts
Expand Down
129 changes: 102 additions & 27 deletions spyder/plugins/editor/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
QToolBar, QVBoxLayout, QWidget)

# Local imports
from spyder.api.config.decorators import on_conf_change
from spyder.api.config.mixins import SpyderConfigurationObserver
from spyder.api.panel import Panel
from spyder.api.plugins import Plugins, SpyderPluginWidget
from spyder.config.base import _, get_conf_path, running_under_pytest
Expand Down Expand Up @@ -64,7 +66,7 @@
logger = logging.getLogger(__name__)


class Editor(SpyderPluginWidget):
class Editor(SpyderPluginWidget, SpyderConfigurationObserver):
"""
Multi-file Editor widget
"""
Expand Down Expand Up @@ -1454,7 +1456,6 @@ def register_editorstack(self, editorstack):
('set_scrollpastend_enabled', 'scroll_past_end'),
('set_linenumbers_enabled', 'line_numbers'),
('set_edgeline_enabled', 'edge_line'),
('set_edgeline_columns', 'edge_line_columns'),
('set_indent_guides', 'indent_guides'),
('set_code_folding_enabled', 'code_folding'),
('set_focus_to_editor', 'focus_to_editor'),
Expand Down Expand Up @@ -1509,8 +1510,16 @@ def register_editorstack(self, editorstack):
False
)

edge_line_columns = CONF.get(
'completions',
('provider_configuration', 'lsp', 'values',
'pycodestyle/max_line_length'),
79
)

editorstack.set_hover_hints_enabled(hover_hints)
editorstack.set_format_on_save(format_on_save)
editorstack.set_edgeline_columns(edge_line_columns)
color_scheme = self.get_color_scheme()
editorstack.set_default_font(self.get_font(), color_scheme)

Expand Down Expand Up @@ -1630,12 +1639,6 @@ def file_renamed_in_data_in_editorstack(self, editorstack_id_str,
if str(id(editorstack)) != editorstack_id_str:
editorstack.rename_in_data(original_filename, filename)

def call_all_editorstacks(self, method, args, **kwargs):
"""Call a method with arguments on all editorstacks."""
for editorstack in self.editorstacks:
method = getattr(editorstack, method)
method(*args, **kwargs)

#------ Handling editor windows
def setup_other_windows(self):
"""Setup toolbars and menus for 'New window' instances"""
Expand Down Expand Up @@ -3005,6 +3008,9 @@ def zoom(self, factor):
def apply_plugin_settings(self, options):
"""Apply configuration file's plugin settings"""
if self.editorstacks is not None:
# Get option names from the tuples sent by Preferences
options = list({option[1] for option in options})

# --- syntax highlight and text rendering settings
color_scheme_n = 'color_scheme_name'
color_scheme_o = self.get_color_scheme()
Expand Down Expand Up @@ -3047,10 +3053,6 @@ def apply_plugin_settings(self, options):
blanks_o = self.get_option(blanks_n)
scrollpastend_n = 'scroll_past_end'
scrollpastend_o = self.get_option(scrollpastend_n)
edgeline_n = 'edge_line'
edgeline_o = self.get_option(edgeline_n)
edgelinecols_n = 'edge_line_columns'
edgelinecols_o = self.get_option(edgelinecols_n)
wrap_n = 'wrap'
wrap_o = self.get_option(wrap_n)
indentguides_n = 'indent_guides'
Expand All @@ -3063,10 +3065,6 @@ def apply_plugin_settings(self, options):
stripindent_o = self.get_option(stripindent_n)
ibackspace_n = 'intelligent_backspace'
ibackspace_o = self.get_option(ibackspace_n)
autocompletions_n = 'automatic_completions'
autocompletions_o = self.get_option(autocompletions_n)
completionshint_n = 'completions_hint'
completionshint_o = self.get_option(completionshint_n)
removetrail_n = 'always_remove_trailing_spaces'
removetrail_o = self.get_option(removetrail_n)
add_newline_n = 'add_newline'
Expand Down Expand Up @@ -3098,7 +3096,6 @@ def apply_plugin_settings(self, options):

finfo = self.get_current_finfo()


for editorstack in self.editorstacks:
# Checkable options
if blanks_n in options:
Expand All @@ -3112,21 +3109,11 @@ def apply_plugin_settings(self, options):
if classfuncdropdown_n in options:
editorstack.set_classfunc_dropdown_visible(
classfuncdropdown_o)

if tabbar_n in options:
editorstack.set_tabbar_visible(tabbar_o)
if linenb_n in options:
editorstack.set_linenumbers_enabled(linenb_o,
current_finfo=finfo)
if autocompletions_n in options:
editorstack.set_automatic_completions_enabled(
autocompletions_o)
if completionshint_n in options:
editorstack.set_completions_hint_enabled(completionshint_o)
if edgeline_n in options:
editorstack.set_edgeline_enabled(edgeline_o)
if edgelinecols_n in options:
editorstack.set_edgeline_columns(edgelinecols_o)
if wrap_n in options:
editorstack.set_wrap_enabled(wrap_o)
if tabindent_n in options:
Expand Down Expand Up @@ -3187,6 +3174,94 @@ def apply_plugin_settings(self, options):
if todo_n in options and todo_o:
finfo.run_todo_finder()

@on_conf_change(option='edge_line')
def set_edgeline_enabled(self, value):
if self.editorstacks is not None:
logger.debug(f"Set edge line to {value}")
for editorstack in self.editorstacks:
editorstack.set_edgeline_enabled(value)

@on_conf_change(
option=('provider_configuration', 'lsp', 'values',
'pycodestyle/max_line_length'),
section='completions'
)
def set_edgeline_columns(self, value):
if self.editorstacks is not None:
logger.debug(f"Set edge line columns to {value}")
for editorstack in self.editorstacks:
editorstack.set_edgeline_columns(value)

@on_conf_change(option='enable_code_snippets', section='completions')
def set_code_snippets_enabled(self, value):
if self.editorstacks is not None:
logger.debug(f"Set code snippets to {value}")
for editorstack in self.editorstacks:
editorstack.set_code_snippets_enabled(value)

@on_conf_change(option='automatic_completions')
def set_automatic_completions_enabled(self, value):
if self.editorstacks is not None:
logger.debug(f"Set automatic completions to {value}")
for editorstack in self.editorstacks:
editorstack.set_automatic_completions_enabled(value)

@on_conf_change(option='automatic_completions_after_chars')
def set_automatic_completions_after_chars(self, value):
if self.editorstacks is not None:
logger.debug(f"Set chars for automatic completions to {value}")
for editorstack in self.editorstacks:
editorstack.set_automatic_completions_after_chars(value)

@on_conf_change(option='automatic_completions_after_ms')
def set_automatic_completions_after_ms(self, value):
if self.editorstacks is not None:
logger.debug(f"Set automatic completions after {value} ms")
for editorstack in self.editorstacks:
editorstack.set_automatic_completions_after_ms(value)

@on_conf_change(option='completions_hint')
def set_completions_hint_enabled(self, value):
if self.editorstacks is not None:
logger.debug(f"Set completions hint to {value}")
for editorstack in self.editorstacks:
editorstack.set_completions_hint_enabled(value)

@on_conf_change(option='completions_hint_after_ms')
def set_completions_hint_after_ms(self, value):
if self.editorstacks is not None:
logger.debug(f"Set completions hint after {value} ms")
for editorstack in self.editorstacks:
editorstack.set_completions_hint_after_ms(value)

@on_conf_change(
option=('provider_configuration', 'lsp', 'values',
'enable_hover_hints'),
section='completions'
)
def set_hover_hints_enabled(self, value):
if self.editorstacks is not None:
logger.debug(f"Set hover hints to {value}")
for editorstack in self.editorstacks:
editorstack.set_hover_hints_enabled(value)

@on_conf_change(
option=('provider_configuration', 'lsp', 'values', 'format_on_save'),
section='completions'
)
def set_format_on_save(self, value):
if self.editorstacks is not None:
logger.debug(f"Set format on save to {value}")
for editorstack in self.editorstacks:
editorstack.set_format_on_save(value)

@on_conf_change(option='underline_errors')
def set_underline_errors_enabled(self, value):
if self.editorstacks is not None:
logger.debug(f"Set underline errors to {value}")
for editorstack in self.editorstacks:
editorstack.set_underline_errors_enabled(value)

# --- Open files
def get_open_filenames(self):
"""Get the list of open files in the current stack"""
Expand Down
13 changes: 10 additions & 3 deletions spyder/plugins/editor/widgets/codeeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4472,7 +4472,10 @@ def event(self, event):
return super(CodeEditor, self).event(event)

def _start_completion_timer(self):
"""Helper to start timer or complete."""
"""Helper to start timer for automatic completions or handle them."""
if not self.automatic_completions:
return

if self.automatic_completions_after_ms > 0:
self._timer_autocomplete.start(
self.automatic_completions_after_ms)
Expand Down Expand Up @@ -4633,7 +4636,8 @@ def keyPressEvent(self, event):
# redefine this basic action which should have been implemented
# natively
self.stdkey_end(shift, ctrl)
elif text in self.auto_completion_characters:
elif (text in self.auto_completion_characters and
self.automatic_completions):
self.insert_text(text)
if text == ".":
if not self.in_comment_or_string():
Expand Down Expand Up @@ -4711,6 +4715,9 @@ def keyPressEvent(self, event):

def _handle_completions(self):
"""Handle on the fly completions after delay."""
if not self.automatic_completions:
return

cursor = self.textCursor()
pos = cursor.position()
cursor.select(QTextCursor.WordUnderCursor)
Expand Down Expand Up @@ -4758,7 +4765,7 @@ def _handle_completions(self):
if (len(text) >= self.automatic_completions_after_chars
and self._last_key_pressed_text or is_backspace):
# Perform completion on the fly
if self.automatic_completions and not self.in_comment_or_string():
if not self.in_comment_or_string():
# Variables can include numbers and underscores
if (text.isalpha() or text.isalnum() or '_' in text
or '.' in text):
Expand Down
17 changes: 7 additions & 10 deletions spyder/plugins/preferences/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,22 @@

# Standard library imports
import ast
import functools
import os.path as osp

# Third party imports
from qtpy import API
from qtpy.compat import (getexistingdirectory, getopenfilename, from_qvariant,
to_qvariant)
from qtpy.QtCore import QSize, Qt, Signal, Slot, QRegExp
from qtpy.QtCore import Qt, Signal, Slot, QRegExp
from qtpy.QtGui import QColor, QRegExpValidator, QTextOption
from qtpy.QtWidgets import (QButtonGroup, QCheckBox, QComboBox, QDialog,
QDialogButtonBox, QDoubleSpinBox, QFontComboBox,
QGridLayout, QGroupBox, QHBoxLayout, QLabel,
QLineEdit, QListView, QListWidget, QListWidgetItem,
QMessageBox, QPushButton, QRadioButton,
QScrollArea, QSpinBox, QSplitter, QStackedWidget,
QVBoxLayout, QWidget, QPlainTextEdit, QTabWidget)
from qtpy.QtWidgets import (QButtonGroup, QCheckBox, QComboBox, QDoubleSpinBox,
QFontComboBox, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMessageBox, QPushButton,
QRadioButton, QSpinBox, QVBoxLayout, QWidget,
QPlainTextEdit, QTabWidget)

# Local imports
from spyder.config.base import _, load_lang_conf
from spyder.config.base import _
from spyder.config.manager import CONF
from spyder.config.user import NoDefault
from spyder.py3compat import to_text_string
Expand Down